双Token认证方案
使用双重Token验证的用户验证方案。
前言
在之前的项目中,我基本都是围绕JWT去做用户校验。JWT天然的无状态方案不需要我们专门在服务端去维护Session表,也不需要我们去做Session的同步,只需要在客户端存储Token,然后在请求时携带Token即可,相当的简便。
但这带来一个问题,在JWT中,我们无法在服务端主动去销毁Token,因为Token是无状态的,无法在服务端去维护Token的状态。即使用户在客户端进行了登出操作,但如果拿到之前的Token放到请求头依然能够正常请求。虽说这对于一般的用户进行正常操作来说是没有什么影响的,但是在浏览器Token是完全暴露的情况下,这就会带来一个安全问题。尤其是简单地使用JWT作为登陆凭证往往会设置较长的过期时间,那么在这段时间内,一旦有人窃取拿到了Token,就可以一直使用这个Token进行操作,这就会带来很大的安全隐患。
解决思路
使用Refresh Token
首先是JWT一般过期时间都比较长的问题,可以通过缩短Token的过期时间来解决。但这又带来了新问题:Token过期后用户需要频繁重新登录,体验很差。
这时候可以用两个Token解决:一个有效期短的Access Token作为登录凭证,一个有效期长的Refresh Token作为刷新凭证。登录成功后服务端返回两者;当 Access Token 过期时,客户端用 Refresh Token 换取新的 Access Token(可选是否同时轮转 Refresh Token)。下面代码示例采用「只刷新 Access Token、Refresh Token 保持不变直到登出或过期」的简化方案。
这样即使真正的验证Token有效期短,也可以通过长时效的Refresh Token来无感刷新验证Token,无需用户重新登陆。而且由于真正的验证Token有效期短,大大缩短了使用非法获取的Token进行非法操作的窗口时间。
-
刷新Token有效期长,用于刷新验证Token由服务端通过httponly-cookie回传给客户端 -
验证Token有效期短,用于验证用户身份 由服务端通过JSON数据回传,由客户端存储在sessionStorage或者直接存储在运行内存中
黑名单
维护一个黑名单,用于存储主动失效的刷新Token。
在用户登出时,服务端将用户的刷新Token加入到黑名单中并清除其对应的cookie,这样用户不得不重新登录。即便用户通过某种手段使用之前的刷新Token去获取新的验证Token