此篇为自己学习过程中的总结,特此记录
一、认证系统演变
1.1 session、cokie实现登录机制
为什么我们需要Cookie和Session?这就需要从HTTP协议说起。 HTTP协议是无状态的,也就是说每次请求都是独立的不受之前请求的影响。它的执行情况和结果与前面的请求和之后的请求都没有直接关系。简单来说就是,对服务器来说每次的请求都是全新的。
状态可以理解为客户端和服务端某次会话产生的数据,那么HTTP的无状态就不会对这些数据进行保存。但是会话中产生的数据又是沃恩需要的,也就是说要保持状态。因此在这样的场景下Cookie就诞生了。
cookie虽然在一定程度上解决了保持状态的需求,但是因为cookie最大指支持4096字节,以及cookie保存在客户端可能被拦截窃取,因此需要一种新的东西,它能支持更多字节且能保存在服务器,有较高的安全性,于是session应运而生。
1.1.1 工作原理
客户端携带登录凭证(用户名、密码)请求服务端,服务端验证通过后生成认证相关的session并保存。然后将对应session_id返回给客户端,客户端把session_id保存在cookie中。此后客户端请求都会携带session_id。服务端可以根据接收到session_id的就能查询到维护的session信息。
优点:
- 可以后台主动操作session(删除修改等操作)
- session保存在服务端,相对较安全
- 结合cookie使用,较为灵活兼容性较好
缺点:
- cookie + session跨域不友好
- 占用大量服务器内存,增加服务器开销
- 分布式环境需要做session共享机制,可将session存储到数据库或redis
- 基于cookie机制容易被CSRF
1.2 Token登录
使用token实现登录的原理也很简单,客户端携带登录凭证(用户名、密码)请求服务端,服务端验证后生成token存储并返回给客户端以后客户端请求头都携带token访问,服务端校验token有效性,有效表示用户已登录
生成的token我们可以存储在redis或者数据库,客户端拿到返回的token后放到请求头,后续请求服务端需要验证客户端请求头是否携带token信息然后拿获取到的token去数据库或redis查询验证token有效性
优点:
- 可操作session: 后台可以控制session失效
- 支持跨域访问:传统cookie是无法跨域的,而将token放在请求头中解决了无法跨域的问题
- 更适用于移动端:当客户端是非浏览器平台时,cookie是无法支持的,使用token就不存在这一问题
- CSRF:由于不再依赖cookie,所以采用token认证方式不会发生CSRF
- 易扩展:在分布式环境中,可以使用redis存储session实现session共享更利于服务扩展,不再受限于传统sess ion限制
缺点:
- session维护在数据库或redis中,需要占用额外资源,每次登录都需要查询验证token有效性
1.3 JWT登录
JSON Web 令牌 (jwt.io/introductio… 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名
1.3.1 JWT结构
Header
通常由两部分组成:令牌类型和使用的签名算法
例如:
{ "alg": "HS256", "typ": "JWT" }
然后被Base64Url编码形成JWT第一部分
payload
令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的语句
例如:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
然后对有效负载进行Base64URL编码形成JSON Web令牌的第二部分
注意,对于签名令牌,此信息虽然受到篡改保护,但是任何人都可以通过解码读取该信息,所以不要将机密信息放到有效载荷中
Signature
要创建签名部分,必须获取编码的标头、编码的有效负载、标头中指定的算法并对其进行签名
例如:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名用于验证消息在此过程中未被更改,并且在使用私钥签名令牌的情况下,可以验证JWT的发件人
1.3.2 JWT登录原理
JWT登录,和上面token机制不同的是,token需要查询数据库或redis验证是否有效,而JWT不用查库,直接在服务端进行校验,因为用户信息及过期时间都在JWT里,只要在服务端进行校验就可以。
优点(和Token比较):
- 不需要维护session信息,节省资源
- 不用每次登录都查询数据库或者redis验证token有效性,直接验证JWT
缺点: 因为JWT是无状态的,所以JWT一旦派发出去,如果后端不增加其它逻辑的话,它在失效前都是有效的。这明显不符合我们有些业务场景,比如用户退出登录、账户被封禁删除、权限角色变化等
解决方案:
- 将JWT存入redis:想让某个JWT失效直接在redis中删除即可,但是这样会导致每次请求都要从redis中查询JWT是否存在的步骤
- 黑名单机制:和上述方案类似,redis中维护一个黑名单,想让某个jwt失效加入黑名单即可