JWT 身份认证模式
基于session 的方式存在的问题
-
服务器端需要存储
session
,并且由于Session
需要经常快速查找,所以通常存储在内存中,或者内存数据库中。如果同时又大量用户在线,就会占用大量的服务器资源 -
当需要扩展时候,创建
session
的服务器可能不是验证session
的服务器,所以还需要将所有session
单独存储并共享,后来又有人想到,把所有的seesionid
放到同一台电脑上,让所有的用户都访问这同一台电脑,但是如果那个存储sessionid
的服务器挂掉了,那就要让所有的用户都得重登。 -
由于客户端使用
cookie
储存SessionID
, 在跨域场景下需要进行兼容性处理,同时这些方法也难以方法CSRF
攻击
Token 认证模式
基于 session
存在的这些问题,所有就有人在想,凭什么让我去保存这些该死的 sessionId,让用户自己存就好了,那么当用户把 认证信息传过来的时候,我怎么判断这个是我颁发的,还是他自己伪造的?这其实就变成了一个验证的问题。
Token 的流程
- 服务端使用用户名、密码进行认证
- 服务端验证用户名、密码正确以后,生成
Token
返回给客户端 - 客户端保存
Token
,访问需要认证的接口时,在 url 参数或HTTP Header
中加入Token
- 客户端通过解码
Token
进行鉴权,返回给客户端需要的数据
Token 的优势
可扩张性
在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。
安全性
请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。
token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。
可扩展性
使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。
Refresh Token
通常 access token
的有效期会比较短(一般10分钟),refresh token
,的时间比较长(比如 7 天),当用户的 access token
过期的时候,可以使用 refresh token
来动态刷新 access token
,如果 refresh token
也过期了,那么用户就只能重新登录了。
JWT 引入 Refresh Token 以后的工作流程
-
用户使用用户名字和密码进行登录
-
服务器端生成有效期较短的
Access Token
,和有效期较长的refresh token
-
访问接口的时候,携带的是
Access Token
-
如果
Access Token
过期了,则用户就会使用refresh token
向刷新接口请求新的access token
-
如果
refresh token
也过期了,那么只能重新登录了
JWT 的劣势
在实际的生产环境中,使用 jwt
逻辑进行鉴权的,其实比较少(最起码,我遇到过的项目,基本没有用的)。这主要是因为使用 jwt
配置较为复杂,且每次通信,都要进行解密token,比较消耗性能。至于其扩展性,现在完全可以在集群内创建一个公用的 redis
存储 sessionId
,就可以实现集群内的服务共享,且只要鉴权的这个服务没挂,就没事。