我曾经使用过一种方法:
那就是在生成jwt令牌时,加入一个固定的参数当做token生成的salt,如果要将一个用户踢出下线,只需要重新生成一下salt的值,然后在拦截器里每次校验这个salt生成的令牌是否与客户端传递的令牌一致!即可判断出这个token是否已被拉黑。
但是这种方法依然在服务器端存储了一定的数据,违反了其无状态性,有没有什么更好的方法实现?
我曾经使用过一种方法:
那就是在生成jwt令牌时,加入一个固定的参数当做token生成的salt,如果要将一个用户踢出下线,只需要重新生成一下salt的值,然后在拦截器里每次校验这个salt生成的令牌是否与客户端传递的令牌一致!即可判断出这个token是否已被拉黑。
但是这种方法依然在服务器端存储了一定的数据,违反了其无状态性,有没有什么更好的方法实现?
web服务本身就是无状态的,何来违反了其无状态性。
什么是有状态?第一次请求需要根据token查db/redis,第二次不需要。这是有状态。
而web服务是每一次都需要根据token查db/redis。所以是无状态的。
没有更好的方案,只能“有状态”
不太同意楼上的观点,HTTP 无状态(stateless)指的是协议本身无状态,一次请求到响应就结束了,再次请求又是新的。
但是 HTTP 协议上的 session 机制,其实是有状态(stateful)的,在无状态的 HTTP 协议上增加了 会话的概念,HTTP Server 需要为每一个 Session(id) 来保存数据,所以是有状态的。
letting the servers maintain a stateful session over the mostly stateless HTTP protocol.
https://datatracker.ietf.org/...
JWT 就属于无状态,因为 Server 并没有为每个“会话”保存状态。而将 JWT token 保存至 Server 的这种行为就打破了无状态,这也是 JWT 这种 Stateless 设计的一个弊端,Server 无法控制客户端的行为。
JWT 再加上 token 存 Server 端,就有点脱裤子放屁的意思了,不如直接 token 存 redis,不用 JWT ……
个人认为 JWT 这种设计比较鸡肋,不适用大多数的业务场景,就连用户禁用这个小功能都做不了,更别提“踢人下线”了
其实你没必要保存salt啥的作为踢人的判断,踢人可以看作是用户对某些接口的一种权限状态,你踢人的时候,去除他对一些接口的访问权限,当权限被禁止,他是在线还是离线,对你来说无关紧要。前端做一个判断,权限被禁就直接下线。
更简单一点的做法,你给他用户信息表增加字段做个标识,如果该用户被标记为禁封,就不允许登录以及访问其它接口。我之前在实际项目中,对一些特定设备的控制就是这么干的,这与token啥的登录状态无关,挺好用。
3 回答2.6k 阅读✓ 已解决
3 回答4.1k 阅读✓ 已解决
8 回答3.7k 阅读
4 回答2.8k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
4 回答1.9k 阅读
jwt 本身就是无状态的,关于踢人,要保持无状态,确实没有特别好的办法。不过有其他办法辅助,比如将token 的过期时间设置得特别短,然后用refresh_token来补充,这本身也是oauth2的原意。说jwt设计鸡肋也不太合适,jwt只是更加接近理想话的水平。不能忽略无状态带来的巨大优势,绝对的并发安全和流畅,不占用资源,不阻塞。就像java中的不可变对象一样,用起来总是不那么如意,但在合适的场景下却能发挥巨大作用。