jwt验证对后端的压力比用session小很多, 毕竟只用对称加密或者hash计算,密钥小可以都存在各台web服务器, 不需要请求redis或者mysql之类的数据库产生io。
[登录踢出]
有时一些应用需要只让一个账号只能在一个浏览器或手机客户端在线,一个手机登录,另一个手机的相同账号需要登录踢出,jwt就比session麻烦一点,不想存数据库需要通知客户端自己删除。
如果客户端出问题没有删除,继续请求,那么应该怎么解决。
简单的解决办法是session和jwt一起用(jwt的refresh token是怎么实现的), jwt设置为5分钟过期,每次请求不续,登录踢出后只有5分钟可用。
还有一种直接在后台管理踢出,一般这种的数据比较少,由每台web服务器存就好了,使用consul配置中心之类的通知进行更新。
或者再简单一点jwt只支持get请求,一般情况下也是get请求居多,一般应该get请求只查询,没大的危害,再严格一点jwt对ip绑定,一个ip请求多的网关会被禁的。更严格一点可以随机几十次请求有一次用session验证。
对于安全有较高要求的应用,jwt是辅助session减少和数据库间的io请求的。
现在流行前后端分离,有时前端要从多个接口取数据再显示到一个界面,进行多次认证的话,jwt效率高很多——多个接口取数据也可以合并,听说阿里有相关的技术
管理后台一般用的人不多,很多也没有前后端分离,对安全的要求也高,只用session就可以了,没有必要为使用新技术而用jwt。
[jwt密钥泄漏]
比如每过一小时自动生成密钥,但这时对session的请求会增加,相当于所有jwt的请求同时过期。
这个需要研究。
简单解决方案,凌晨自动更新密钥。
[remember]
php框架laravel remember_token的信息存在关系数据库的user表
这个是laravel实现的jwt记住我的功能的方式。用session也是一样,存redis的过期了,再到数据库里取认证,实现冷热数据的分离。
但有不方便的地方:
比如我在一个客户端退出了,对这个remember_token怎么办?
方案1:
退出后我更新user表的remember_token, 再通知别的客户端更新remember_token。
问题如下:
如果更新时没有网,电脑或者浏览器是关的,就通知不到。
通知的形式一般是不加密的,所以不能直接告诉客户端remember_token, 客户端收到通知后再用https请求服务器,这时客户端的remember_token的又是过期的,只能看session过期没。
方案2:
只删除客户端remember_token 的cookie, 自然别的客户端还可以用remember_token。直接在后台管理踢出的情况,把所有客户端的remember_token失效问题也不大。
改善1:
所以要新增一个user_remember表
由用户id、客户端类型、token、过期时间 等组成。用户id和客户端类型为主键, 或者用户id和token为主键。
相比直接用user表的情况可以解决上面的问题, 但要判断主键是否存在,麻烦了一点。
改善2:
或者, user表里存一个json, mysql和pgsql都支持,只是主流orm都不支持json,要手写比较麻烦点。
json 以token为key时,还要对这个json加个专门的version进行乐观锁管理,加个最早的过期日期, 定时删除过期的token。
结论:
方案2最简单, 但非常不安全。
改善1合适于一个账号可以在很多客户端无限制登录
改善2合适于只让一个账号只能在一个浏览器或手机客户端在线的情况。
[从opencart学到的]
opencart的session里只存了用户的id, 和用户相关的信息是通过这个id再从数据库取得的。
这里的好处很明显,session是用于验证权限的,存别的信息的话会增加权限验证时的io。
当前用户的一些状态信息可以基于session_id存缓存,不重要的存cookie的话问题也不大,如果加密存cookie的话io会比较大一点——经过加密和base64转码。
和用户相关的信息如果经常要取,也可以基于用户id存缓存里,缓存找不到再取数据库。