Cookie
Cookie是一种小型的文本文件,由网站在用户访问时存储在其计算机或移动设备上,Cookie主要用于跟踪、识别和存储有关用户的信息。
简单来说Cookie就是用来存储某些后端发送给前端的数据,例如我们登陆后,后端会返回一个登录凭证,这样子你才能正常执行网站登录之后的功能。
我们的session和token其实就大部分作为一个登录凭证使用
我们Cookie就是来存储类似的这种东西,我们每次在域名内跳转的时候,我们都默认附加这个Cookie请求,这样子我们就可以保存登录状态来操作
例如我是在bilibili这个域名登录的
我点开其他视频的时候,我是在这个域名内跳转
例如这样子,但是我们跳到了不同的界面,我们还是保持登录状态的,这就是Cookie的作用
Cookie可以在域名内跳转的时候保存一些我们想保存的东西,
所以那种保持登录状态和7天免登录就是Cookie的用处。
所以Cookie其实和Session和Token是不同的东西,我们不要搞混了
但是Session和Token是类似的东西,是一种保持登录状态的东西,是一种登录凭证
Session
然后我们来讲讲Session
Session是我们的服务器里面的一个东西,例如我们的小猫咪Tomcat服务器
我们的Session是由我们的服务器生成,然后Session这个东西我们保存到我们的服务器里面,
我们Session会生成一个叫SessionId的东西返回给前端,然后如果我们检测到我们由SessionId这个和东西我们就可以操作我们的服务器里面的Session
例如我们可以往我们的Session里面存东西,像下面那样
看到了这个Context这个东西了吗,这个东西就是可以做上下文的
我们存进上下文的东西是可以全局使用,调用的
这个的意思是,我们用Session来统计,其实不同的浏览器执行时,我们拿到的SeesionId是不同的,所以我就做了个简单的登录统计,我们往这个全局上下文的“olcount”存储,如果session!=null,我们就加1,这个就是简单的往Session的Context上下文里面存的东西逻辑
其实我们也可以直接往session里面存,session.set就行了
例如我们写代码的时候,像调用一些东西,例如我们登录,然后像后面调用它的用户名
我们就Session.set("username","kira"),我们往session里面存了个username的变量,变量的值是kira,然后我们后面写逻辑的时候,想得到我们当前用户的用户名我们直接session.get("username"),就把kira这个用户名给拿出来了
总的来说就是,Session是在我们的服务器生成的,然后我们生成一个SessionId给前端存储到Cookie里,有了SessionId我们就可以操作我们的服务器里面对应的Session以及里面的方法
Seesion是一种服务器自己生成的东西,返回给前端的SeesionId是我们的登录凭证
但其实Session有缺点,如果Seesion过多它会占用服务器的内存,然后Session的很多东西都是服务器生成的,我们这种后端很难灵活地操作和修改,例如它设定这个Seesion的过期时间为10分钟,我们只想让一个Session30分钟过期,其他Seesion保持不变,我们只能直接修改服务器配置改成30分钟,但修改服务器Seesion过期时间配置的话,其他所有的Seesion都会跟着修改过期时间,无法做到某个特例不同
Token
然后我们来讲Token
Token是一种基于加密算法,由后端自己做的一种登录凭证
而Seesion是一种服务器生成的东西,SessionId是服务器生成的登陆凭证
区别在于:一个是服务器规定好生成的,一个是后端自己基于加密算法做好的,我们的操作主体是不同的,一个是服务器,一个是后端
我们可以用UUID来随机生成一个Token,UUID其实也是一种算法,例如我们这样子,生成一个东西来当作Token
我们使用正确的密码成功登录之后,我们用生成的UUID,把它存到我们的Redis里面,设置例如30分钟的过期时间
最重要的一点来了,我们要把这个东西返回给前端
我们一般都是,把这个Token(我是用UUID做的)存到请求头里面,请求头里的参数名是Authorization,把我们的uuid存到这个请求头的变量里面
然后我们在全局拦截器里面弄一个操作逻辑,就是任何请求,我们都要有一个判断就是判断用户是否是登录状态,如果我们的Authorization不为空,且uuid的值和后端里存的uuid可以对上,那么就可以确认这个用户是登录状态的
怎么样?之前我们是用SessionId来找到服务器对应session判断用户是否是登录状态,
现在是我们用Token去找对应的东西是否存在来判断用户是否是登录状态
所以Session和Token其实有很多类似的地方,但是Session里面可能有些操作方法什么的可以调用,不仅仅只有个SessionId作为登录凭证,而Token大部分时间是做登录凭证的,反正我还没了解到Token的其他大用途。
还记得之前提到的Session的一个小问题吗?
修改服务器Seesion过期时间配置的话,其他所有的Seesion都会跟着修改过期时间,无法做到某个特例不同
但是如果我们用Token然后存到我们的Redis里面的这个逻辑的话,我们可以用Redis来给不同的Token来设置过期时间,这样子就可以设置不同的用户的过期时间了是吧?
例如A用户10分钟过期,B用户20分钟过期,C用户30分钟过期
但是如果我们用session的话,我们无法做到这种多个不同的过期时间,我们只能统一所有的session都是一个过期时间,所以Token的优点就在这里。而且Token的话不会像Session那样占用服务器内存,它只是一个小数据,我们存到数据库里面使用,还可以随意设置过期时间。
JWT
jwt其实就是token的另一种实现方式,上面的例子我是用UUID来演示我们的token的,然后存到redis里面设置过期时间
而JWT的话就更加简便了,我就拿黑马课程的这章节来举例子
实战篇-07_JWT令牌_哔哩哔哩_bilibili
里面提供了一个生成jwt的工具类,有特定的算法,和我们的那个uuid的算法不同,下面的就是提供的jwt工具类,它把jwt常用的方法非封装成了工具类
首先我们要引入jwt的依赖
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version>
</dependency>
我们的这个jwt算法生成工具类的话,可以指定生成算法
其中jwt是由这三部分组成的
分别是 Header(头) Payload(有效载荷) Signature(签名)
有效载荷里面可以存储一些自定义信息,我们可以把想要的信息通过jwt工具类加密,变成有效载荷
签名可以防止Token被修改,签名里面有指定我们需要的加密算法,这样子我们拿到后端解析的时候,签名可以解析出对应的算法,然后用对应的算法把我们的token以及token里面的信息成功解析出来
你看下面我们用工具类造token的时候有三个逻辑
添加信息
添加过期时间
指定我们的加密算法
所以我们就不需要按照我一开始的逻辑那样用Redis来设置我们的过期时间了
因为我们的过期时间的设置可以存到我们的有效载荷里面,然后我们后端的jwt工具类解析token,就可以知道这个token过期没有了,就不用存到我们的Redis里面了
所以jwt只是一种现在主流的token的实现方式,不过他确实简便然后复杂程度也比我举例子的那个uuid高,所以我们以后用jwt就行了,不用UUID。
但是有一个应用场景,会让我们的jwt的使用出问题,就是我们更新密码的时候,按理来说我们会生成新的token,但是我们旧的token不能自动过期
所以我们要结合redis,把token存到我们的redis中,如果我们修改了密码,我们就手动让旧的token过期,然后让新的token存到redis里面然后生效。
其实我觉得既然要结合redis,那么我们的token没必要在弄的时候就设置过期事件,直接用redis设置过期时间其实也是一种思路,不过其实都一样,redis在这起到的作用就是在更新密码的时候主动过期我们的token。