一篇文章带你走进cookie,session,Token的世界

一篇文章带你走进cookie,session,Token的世界

前言

状态的HTTP协议

一天,你有个需求,你要去超市买一瓶可乐。 到了超市买了可乐,你告诉售货员,下次给我准备下雷碧,我下次来拿。 第二次,你去超市拿雷碧,售货员说他不记得你什么时候说要准备雷碧。 这次你学聪明了,售货员给你写了个纸条,上面有超市的章印,下次你带着纸条来,买上了超市 给你准备的雷碧

  • http超文本传输协议:Hyper Text Transfer Protocol
  • http不会为了下次连接所需要的信息而维护这次连接
  • 就像你去超市买可乐,买完就结束了,它不会记录你告诉他的信息,不会记录你下次还要买雷碧,下次他也不知道你曾经来过
  • 顾名思义无状态是指,当浏览器发送请求给server的时候,server响应,可是同一个浏览器再发送请求给server的时候,他会响应,可是他不知道你就是刚才那个浏览器,简单地说,就是server不会去记得你,所以是无状态协议。而DNS是有状态协议。
  • 再举个例子,像购物车,你买东西加入购物车,如果http协议的话,刷新页面,购物车就为空了。
  • 一、cookie

    cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据。跟服务器没啥关系,仅仅是浏览器实现的一种数据存储功能。

    cookie由服务器生成,发送给浏览器,浏览器把cookie以KV形式存储到某个目录下的文本文件中,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间。所以每个域的cookie数量是有限制的。

    如何设置

    客户端设置

    document.cookie = “name=xiaoming; age=12 “

    • 客户端可以设置cookie的一下选项: expires, domain, path, secure(只有在https协议的网页中, 客户端设置secure类型cookie才能生效), 但无法设置httpOnly选项

    设置cookie => cookie被自动添加到request header中 => 服务端接收到cookie

    服务端设置

    不管你是请求一个资源文件(如html/js/css/图片), 还是发送一个ajax请求, 服务端都会返回response.而response header中有一项叫set-cookie, 是服务端专门用来设置cookie的;

    • 一个set-cookie只能设置一个cookie, 当你想设置多个, 需要添加同样多的set-cookie
    • 服务端可以设置cookie的所有选项: expires, domain, path, secure, HttpOnly

    Cookie,SessionStorage,LocalStorage

    HTML5提供了两种本地存储的方式 sessionStorage 和 localStorage;

    二、Session

    Cookie是存储在客户端方,Session是存储在服务端方,客户端只存储SessionId

    在上面我们了解了什么是Cookie,既然浏览器已经通过Cookie实现了有状态这一需求,那么为什么又来了一个Session呢?这里我们想象一下,如果将账户的一些信息都存入Cookie中的话,一旦信息被拦截,那么我们所有的账户信息都会丢失掉。所以就出现了Session,在一次会话中将重要信息保存在Session中,浏览器只记录SessionId一个SessionId对应一次会话请求。

    1@RequestMapping(“/testSession”) 2@ResponseBody 3public String testSession(HttpSession session){ 4 session.setAttribute(“testSession”,”this is my session”); 5 return “testSession”; 6} 7 8 9@RequestMapping(“/testGetSession”)10@ResponseBody11public String testGetSession(HttpSession session){12 Object testSession = session.getAttribute(“testSession”);13 return String.valueOf(testSession);14}

    这里我们写一个新的方法来测试Session是如何产生的,我们在请求参数中加上HttpSession session,然后再浏览器中输入http://localhost:8005/testSession进行访问可以看到在服务器的返回头中在Cookie中生成了一个SessionId。然后浏览器记住此SessionId下次访问时可以带着此Id,然后就能根据此Id找到存储在服务端的信息了。

    此时我们访问路径http://localhost:8005/testGetSession,发现得到了我们上面存储在Session中的信息。那么Session什么时候过期呢?

    • 客户端:和Cookie过期一致,如果没设置,默认是关了浏览器就没了,即再打开浏览器的时候初次请求头中是没有SessionId了。
    • 服务端:服务端的过期是真的过期,即服务器端的Session存储的数据结构多久不可用了,默认是30分钟。

    既然我们知道了Session是在服务端进行管理的,那么或许你们看到这有几个疑问,Session是在在哪创建的?Session是存储在什么数据结构中?接下来带领大家一起看一下Session是如何被管理的。

    Session的管理是在容器中被管理的,什么是容器呢?Tomcat、Jetty等都是容器。接下来我们拿最常用的Tomcat为例来看下Tomcat是如何管理Session的。在ManageBase的createSession是用来创建Session的。

    1@Override 2public Session createSession(String sessionId) { 3 //首先判断Session数量是不是到了最大值,最大Session数可以通过参数设置 4 if ((maxActiveSessions >= 0) && 5 (getActiveSessions() >= maxActiveSessions)) { 6 rejectedSessions++; 7 throw new TooManyActiveSessionsException( 8 sm.getString(“managerBase.createSession.ise”), 9 maxActiveSessions);10 }1112 // 重用或者创建一个新的Session对象,请注意在Tomcat中就是StandardSession13 // 它是HttpSession的具体实现类,而HttpSession是Servlet规范中定义的接口14 Session session = createEmptySession();151617 // 初始化新Session的值18 session.setNew(true);19 session.setValid(true);20 session.setCreationTime(System.currentTimeMillis());21 // 设置Session过期时间是30分钟22 session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);23 String id = sessionId;24 if (id == null) {25 id = generateSessionId();26 }27 session.setId(id);// 这里会将Session添加到ConcurrentHashMap中28 sessionCounter++;2930 //将创建时间添加到LinkedList中,并且把最先添加的时间移除31 //主要还是方便清理过期Session32 SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);33 synchronized (sessionCreationTiming) {34 sessionCreationTiming.add(timing);35 sessionCreationTiming.poll();36 }37 return session38}

    到此我们明白了Session是如何创建出来的,创建出来后Session会被保存到一个ConcurrentHashMap中。可以看StandardSession类。

    1protected Map sessions = new ConcurrentHashMap();

    到这里大家应该对Session有简单的了解了。

    Session是存储在Tomcat的容器中,所以如果后端机器是多台的话,因此多个机器间是无法共享Session的,此时可以使用Spring提供的分布式Session的解决方案,是将Session放在了Redis中。

    三、Token

    1、什么的Token

    Token是首次登陆时由服务器下发,作为客户端进行请求的一个令牌,当交互时用于身份验证的一种验证机制,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

    2、Token的作用

    • Token完全由应用程序进行管理,所以它可以避开同源策略
    • Token可以避免CSRF(跨站请求访问)攻击
    • Token可以是无状态的,可以在多个服务器之间共享
    • 使用Token减轻服务器的压力,减少频繁的查询数据库。

    3、Token身份认证的过程

    • 用户通过用户名和密码发送请求
    • 程序进行验证
    • 程序返回一个签名的token给客户端
    • 客户端进行存储token,并且用于每次发送请求
    • 服务器端进行验证token并返回数据

    4、Token的存储位置

    • 存储在localStorage中
    • // 存储token到ls const { token } = res.data; window.localStorage.setItem(‘jwtToken’, token);

    优点:没有时间限制的存储,会一直存放在浏览器中。

    缺点:由于LocalStorage 可以被 javascript 访问,所以容易受到XSS攻击。所以可以在一个统一的地方复写请求头,让每次请求都在header中带上这个token, 当token失效的时候,后端会返回401,这个时候在你可以在前端代码中操作返回登陆页面,清除localstorage中的token。(适用于 ajax请求或者 api请求,可以方便的存入 localstorage)另外,需要应用程序来保证Token只在HTTPS下传输。

    • 存储在cookie中

    优点:可以防止 csrf攻击,因为 csrf只能在请求中携带 cookie,而这里必须从 cookie中拿出相应的值并放到 authorization 头中。实际上cookie不能跨站(同源策略)被取出,因此可以避免 csrf 攻击。(适用于 ajax请求或者 api请求,可以方便的设置 auth头)

    5、Token处理过期时间

    在我的vue项目中,我将Token存储在了localStorage中,有处理过Token过期,我是这样做的:

    created() { if (localStorage.jwtToken) { const decoded = jwt_decode(localStorage.jwtToken); //获取当前时间 const currentTime = Date.now() / 1000; //检测token是否过期 if (decoded.exp < currentTime) { //跳转到登录页面 this.$router.push('/login'); //其他处理 … } else{ //没有过期的处理; } }

    四、总结

    cookie,session,Token没有绝对的好与坏之分,只要还是要结合实际的业务场景和需求来决定采用哪种方式来管理回话,当然也可以三种都用。

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    (0)
    用户投稿
    上一篇 2022年6月25日
    下一篇 2022年6月25日

    相关推荐

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息