在上文,我们实现了基于SpringBoot项目的API接口开发,并实现 API结果统一封装、支持跨域请求等等功能,接下来做的是开发登录接口,实现一套统一鉴权的用户身份认证的机制。
我已经提前和狗哥一起讨论确定了认证机制,会采用目前流行的基于JWT的Token用户身份认证机制,主流程如下:
生成Token
返回给前端;保存Token
,以后每次请求API都会携带Token
,后端校验Token
通过就正常返回数据;校验Token
已失效,这时再从第1步重新开始。
为什么这么选型?我们都考虑了哪些点?是不是拍脑袋来的?
我希望你能有这些疑问,而不仅仅是被动的接收,主动思考=真正的理解!
OK,那我也很乐意和大家一起探讨:怎么做好用户身份认证!
所以,在实战写代码之前,我们有必要深入理解Session、Token、JWT,都是什么?都有什么优缺点?
同时,希望通过本文,大家能对Session、Token、JWT有深入透彻的理解,相信本文一定会让你有所收获!
PS,完整的用户身份认证代码早已实现,和狗哥也已联调通过,正在赶工博文,预告一下我将分三篇来写,非常详细,料很足,准备好发车喽,Let’s go!
因为可能还有很多同学还不清楚上下文,所以简单介绍一下这个专栏要做的事:
天罡老哥和狗哥(博客主页)有意
从0到1
带大家搭建一个SpringBoot+SpringCloud+Vue
的前后端分离项目! 打造一个短小精悍、技术主流、架构规范的前后端分离实战项目!我负责后端,狗哥负责前端! 目的就是让大家通过项目实战,学到一些真东西,将所学理论落地,助力有心强大的你更快的成长!开启你的工作之旅,让开发游刃有余!
详细的后端规划和后端大纲思维导图在开篇已经给出,专栏的总进度如下:
SpringBoot+Vue前后端分离项目实战 - 服务端部分 |
---|
1. 基于SpringBoot+SpringCloud+Vue前后端分离项目实战 --开篇 |
2. 天狗实战SpringBoot+Vue(一)环境安装 |
3. 天狗实战SpringBoot+Vue(二)项目结构搭建(上) |
4. 天狗实战(二)SpringBoot API开发详解 --SpringMVC注解+封装结果+支持跨域+打包(下) |
5. Maven依赖加载不进来? 依赖加载失败? 你值得掌握如何排查的方法 |
6. 实战Git常用操作(IDEA界面+命令):初始化(init)、忽略文件(.gitignore)、提交(commit)、查看提交记录(log)、创建+切换分支(branch) |
Vue + SpringBoot前后端分离项目实战 - 前端部分 |
1. 手把手带你做一套毕业设计-征程开启 |
2. 我应该把毕业设计做到什么程度才能过关? |
3. 做毕业设计,前端部分你需要掌握的6个核心技能 |
4. 基于Vue+Vue-cli+webpack搭建渐进式高可维护性前端实战项目 |
5. 基于Vue+Less+axios封装+ElementUI搭建项目底层支撑实战 |
6. 使用Vue+vue-router+路由守卫实现路由鉴权功能实战 |
提前说明:
因为HTTP 是无状态的协议,每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人,所以就需要在用户登录后进行登录态的管理。
其中有一种是基于Session的方式,是一种记录服务端和浏览器会话状态的机制,大致的流程如下:
唯一标识SessionId
,比如根据用户ID+加随机盐salt,然后进行各种加密生成
基于Token的认证方式,又分为两种:
有状态的Token方式,服务端需要保存Token数据
比如, 将基于Cookie的Session方式变一变,不基于Cookie了,而是由前端自行维护Token,大致的流程如下:
唯一标识TokenId
,比如根据用户ID+加随机盐salt,然后进行各种加密生成
当Token不需要保存除用户ID之外的信息时,Token就等于TokenId,只是保存的信息变少,但仍然需要服务端保存,例如保存在内存中的话就是数据结构用Map还是Set的区别,或者Map的value是不是空的区别。
当然还有其它场景:
无状态的Token方式,服务端不用保存Token数据,是不是听上去很历害?大致的流程如下:
生成Token
返回给前端;保存Token
,比如保存在localStorage等,请求API时控制携带Token,服务端接收后校验Token
: JWT (JSON Web Token) 是一种开放标准(RFC 7519)定义的JSON对象,本质是一个字符串,正是无状态Token中的一种。那它是如何做到不用服务端保存,仅通过自身就能完成校验?
这和人民币防伪有点类似,是因为它本身既包含用户信息
等数据,也包含过期时间
和数字签名
,虽然数据经过传输,但接收方仍可以直接校验它是否过期
、是否被篡改
!
还没理解?那我们看一下它的组成:
如上图右侧是解码后的数据,左侧是JWT字符串,由图中3种颜色代表的3个部分组成(以逗号连接):
1Header.2Payload.3Signature
元数据
,定义了生成签名的算法以及 Token 的类型。
{
"typ": "JWT",
"alg": "RS256"
}
载荷
,是传递数据的载体,包含7个内置字段:
String ISSUER = "iss"; // 发行人
String SUBJECT = "sub"; // 主题
String EXPIRES_AT = "exp"; // 失效时间
String NOT_BEFORE = "nbf"; // 在此之前不可用
String ISSUED_AT = "iat"; // 发布时间
String JWT_ID = "jti"; // JWT id值
String AUDIENCE = "aud"; // 用户
重点是 exp 失效时间 ,其它可选使用,例如:我可以将 iss 指定保存userId
用户信息就保存在这里,上面7个不够的话,还可以自定义字段,例如:我自定义了userName:
{
"sub": "TgAuthSSO",
"nbf": 1679984611,
"iss": "1",
"exp": 1679984911,
"userName": "张三",
"iat": 1679984611
}
注意:payload中数据默认未加密,所以
不适合放隐私信息字段
,比如用户的密码等,防止信息泄露。
签名
,这是JWT防止内容被篡改的关键!
通过使用 Header 里面指定的签名算法,对Payload和Header加密而生成。
数据被签名加密后,可以有效防止内容被篡改。
例如:RSA算法,目前仍是非常可靠的加密算法,极难破解!
【无状态】是相对【有状态】而言,【有状态】是指服务器端需要保存数据。
JWT由于其自带校验的所有数据,本身就可以验证Token是否被篡改、是否合法、是否过期,所以不需要在服务器存储Token,对于分布式场景省去了很多麻烦,更主要的是节省了服务器资源!
能够在Payload中自定义存储字段,保证了扩展性,可以把常用数据写进去,避免数据的二次读取。