前言
用SpringBoot做一个项目,都要写登录注册之类的方案
使用Cookie或Session的话,它是有状态的,不符合现代的技术
使用Security或者Shiro框架实现起来比较复杂,一般项目无需用那么复杂
使用JWT它虽然是无状态的,也可以载荷用户数据,但还是有很多缺点
- 缺点1:设置过期时间后,无法强制让它过期,在有效期内它始终可用
- 缺点2:一次性的,如果用户数据有变,只能重新生成新的JWT
- 缺点3:安全性,它是base64加密的,如果载荷有重要数据,可以被抓包解析
JWT不适合登录鉴权,适合应⽤场景:⼀次性验证,比如⽤户注册后发⼀封邮件让用户在有效期内激活账户
所以很多项目用的都是Redis+Token方案,简单方便问题少
流程 + lua优化:
-
设置一个拦截器,不校验登录接口,拦截其他接口
-
登录接口接收前端传来的用户名密码,去数据库查询该用户名是否存在,该密码是否正确
-
如果正确则表示登录成功,调用生成Token方法,返回Token给前端
-
Token使用用户id或账号+时间戳+UUID用MD5加密的一串字符串(不建议用其他数据,因为id或账号极少变更的,变更会增加复杂性)
-
生成后存储到Redis,把Token当作键,用户数据当作值,并设置过期时间
-
生成Token的方法中,还得防止重复调登录接口,不停生成不同的Token,所以先判断数据库中是否存在键,所以保存token键到redis的同时要在redis中再增加一条用户ID为键Token为值的数据,可以验证该用户是否已经生成过token,如下:
这个验证token的是已登录后其他请求通过拦截器中验证token的
-
先请求一次reids拿过期时间来判断,再选择生成或者延长
关于Token续签(延长过期时间)
假如设置Token五个小时过期需要重新登录,其他的博客可能有刷新token,这些工作需要前端去配合调用,无疑增加了前端和后端的工作量。所以考虑直接用已存在的Token延长时间,因为Token本身是md5加密的,所以安全性还是可以的 -
注意到没,判断和生成和续签都需要两次redis请求,一次判断时间,一次读写Token,
这可能就会导致数据不一致问题,懂了吗?所以这部分操作全部交由lua处理
登录方法这个lua脚本中既判断了存在,又判断了是否需要延期,又可以只生成一个token,且只需要请求一次redis。接下来是校验其他接口方法,同时也做了验证和续期
这样登录和校验续期都只需要请求一次redis即可,类似分布式锁的实现了,相当于把token当作锁。方案只要配置WebMvcConfigurer
自定义一个拦截器,再写一个TokenUtil就好了,是不是很简单
虽然方案还有一些不完美的,但是不影响性能和使用。有更好的意见大家提出~
原创不易,请勿盲目copy!