1.JWT的优势在于无状态,如果非要结合redis等相关nosql来进行一些方案的处理,我觉得是没有必要的。这样还不如直接使用session集群。
2.那么针对JWT就会有几个问题
(1)退出登录,需要把token无效化
(2)修改密码,需要把token无效化
(3)单用户登录,需要进行判断
其实(1)(2)是属于差不多的类型。
这两种情况的处理就比较相似了。
那么我们首先考虑jwt存的是什么,我们假设为{"userId":1,"version":1}
我们先考虑简单处理—redis
退出或者改密码的时候我建议把version提升一个版本(2)。以userId为key,version为value放进hash里,那么每次jwt进来的时候就会去redis中根据userID获取version,发现有的话,那么就会对比version,如果目前version低于redis中的version的话,那么就会拦截下来。
好了 ,这就是一个简单的处理方式。那么接下来分析一下优缺点。
优点:
(1)不用考虑数据的一致性,因为都是从一个地方进行读取
缺点:
(1)每个jwt都需要去redis中进行对比,网络开销容易形成瓶颈
那么如何在继承优点的情况下解决缺点喃?
这就涉及到共享内存的概念了。利用本地内存进行解决。那么关键的问题是如何把redis中的数据同步到每个JVM当中喃?这就涉及到了事件通知了,这里有几种选择(1)MQ,如果过期时间较长,且必须保证安全性,那么这个时候选择MQ作为事件的通知选择非常不错。(2)redis的pub/sub模式,轻量级
当然这个地方也有一个缺点。就是完全依靠了内存,假设这个时候需要重启服务器了,那么之前的token也就不再了。
所以需要提供一种弥补机制,那么这个时候,我会选择把数据备份一份给redis或者数据库,每次重启的时候就会去拉取到每个JVM当中。这样就能解决网络开销的问题了。
那么针对(3)这个问题,比较复杂,需要结合多种情况考虑
(1)在APP下,首先,你登录的时候,我会推送消息给之前的机器,让他帮你强制下线。然后就是处理JWT
可以在JWT中保存{"userId":1,"version":1,"app":"appId"}这样的流程就和上面一样了
(2)在纯web下,那么就只能拦截掉