黑马点评-短信登录

基于Redis实现短信登录

0.前言:

短信验证登录过程中需要共享session

  • 1.发送短信验证码:保存验证码到session
  • 2.短信验证码登录注册:根据手机号查询用户,如果是新用户要先进行注册,再保存用户到session
  • 3.验证登录状态:cookie中有sessionID,判断用户是否存在,进行拦截或者保存到ThreadLocal,再放行

问题:

  • 每个tomcat中都有一份属于自己的session,多台Tomcat不共享session存储空间,切换时数据丢失

替代要求:

  • 数据共享
  • 内存存储,数据处理速度快
  • key,value结构

故选择Redis进行解决

1.采用Redis的业务流程:

发送验证码和登陆注册 登陆注册和校验登陆状态

细节:

1.key和数据结构的选择:
  • 保存验证码:用手机号作为key
    • 手机号是唯一的,并且恰好与验证码绑定
    • 采用String类型存储code
  • 保存用户对象:用随机生成的token作为key
    • token需要传递给前端,并在每次请求中被携带,用手机号会有泄露风险
    • 采用Hash结构存储用户对象,相比String采取Json格式,Hash结构每个字段相互独立,可以单独CRUD,并且内存占用更少
2.选择合适的有效期:
  • token要设置一定的有效期,用户长期不操作,就失去登录状态
3.选择合适的存储粒度DTO
  • 用户对象本身的信息是很丰富的,还包括手机号,密码等隐私信息,在登陆阶段不需要保存和传递这么多信息,可以新建一个UserDTO类来代替

2.技术要点:

ThreadLocal:

  • 在threadLocal中,他的put方法和他的get方法, 都是先从获得当前用户的线程,然后从线程中取出线程的成员变量map,只要线程不一样,map就不一样,所以可以通过这种方式来做到线程隔离
  • 所以可以实现每个用户的保存和相关信息的读取

User转Hash存储:

  • userDTO转Map再存储到Redis过程中,由于使用的是StringRedisTemplate要求所有的字段都是String类型,但是id是Long类型的,所以需要再进行一步手动转化
1
2
3
4
Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),
CopyOptions.create()
.setIgnoreNullValue(true)
.setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));

刷新token有效期优化:

在只有一个拦截器的情况下,拦截器里的过程:

  • 获取token信息
  • 查询Redis的用户,不存在就拦截,存在就继续
  • 保存到ThreadLocal中
  • 刷新token有效期
  • 放行

那么如果用户进行了不需要登录验证的操作,比如查看首页,那么拦截器不会拦截,token就得不到刷新,是有问题的。

解决:增加一个拦截一切路径的拦截器

第一个拦截器:(所有路径)

  • 获取token信息
  • 查询Redis的用户
  • 保存到ThreadLocal中
  • 刷新token有效期
  • 放行

第二个拦截器:(需要登陆的路径)

  • 不存在就拦截,存在就继续

完美实现token的及时刷新


黑马点评-短信登录
http://example.com/2024/02/01/网上技术学习/短信登录/
作者
jhxxxxx
发布于
2024年2月1日
许可协议