那如果我们非要实现强制用户登出要怎么办呢?
可以采用类似oauth2.0协议中的做法,认证后颁布2个token,access token和refresh token。
- access token访问令牌为一个JWT,设置一个较短的过期时间,比如1小时。访问令牌每次调用后端服务都需要携带,往返网络的频率非常高,暴露的可能性就越大,设置较短的过期时间也可以降低安全风险。
- refresh token刷新令牌,可以不为JWT,设置一个较长的过期时间,比如1个月。刷新令牌主要用来换取新的access token。因为其仅在访问令牌要失效或已经失效时才会被传递给服务端,较长的过期时间并不会有太大的安全风险。颁发token的时候,仅将刷新令牌保存在redis并设置过期时间。当使用刷新令牌换取新的访问令牌时,需要判断redis里是否存在该刷新令牌,如果不存在,则刷新失败,用户就需要重新登录。
客户端要长时间维护登录态,就需要当访问令牌失效后,自动使用刷新令牌获取新的访问令牌。或者在访问令牌失效之前,提前刷新令牌。
现在我们想要踢人,只需要将用户相关的刷新令牌从redis里删除。当前的访问令牌失效后,自然也没有办法再刷新令牌了。从而达到强制用户登出的目的。
这么设计有个缺陷就是强制用户登出不是及时的。需要有一个等待访问令牌过期的时间。如果希望及时性高点,可以将访问令牌的过期时间设置短一点,但刷新token的频率就会升高。这个需要根据自己的业务进行权衡。
每次调用服务api时仍然是原汁原味的jwt无状态认证,无需访问任何中心存储。仅在刷新访问令牌的时候需要访问中心存储。也算是一种折中的方案。