点评--day02--2.1 短信登录业务逻辑梳理

5 阅读3分钟

💡 核心背景:为什么引入 Redis?

在单体架构中,我们通常使用 Tomcat 的 Session 来存储登录用户信息。但在集群部署下,多台 Tomcat 服务器之间的 Session 是不共享的,会导致用户在 A 服务器登录后,请求路由到 B 服务器时又变成未登录状态。

为了解决这个问题,我们引入了 Redis 作为统一的数据存储中间件,实现跨服务器的状态共享。


🔄 短信登录核心三大流程

整个基于 Redis 的短信登录系统可以拆解为三个连贯的动作:

1. 发送短信验证码流程

这是用户交互的第一步,重点在于临时数据的存储

  • 校验手机号: 接收前端传来的手机号,使用正则表达式验证格式是否合法。
  • 生成验证码: 如果合法,利用工具类(如 Hutool 的 RandomUtil)生成一个 6 位随机数字验证码。
  • 存入 Redis: 以手机号为标识(如 login:code:173xxx),将验证码作为 String 类型存入 Redis,并设置一个较短的过期时间(例如 2 分钟)。
  • 发送短信: 调用第三方短信服务将验证码发送给用户(项目中通常通过控制台日志模拟发送成功)。

2. 验证码登录 / 注册流程

这是核心业务逻辑,重点在于长效 Token 的生成与数据结构的转换

  • 验证验证码: 接收用户提交的手机号和验证码,从 Redis 中查出对应的验证码进行比对。
  • 查询用户: 如果验证码一致,根据手机号去 MySQL 数据库查询该用户是否存在。
  • 自动注册: 如果用户不存在,则系统自动为其创建一个新用户记录,并保存到数据库中。
  • 生成 Token: 生成一个随机的 UUID 作为 Token(令牌),这将替代传统 Session ID 的作用。
  • 存入 Redis: 将查询到或新创建的用户信息转换为 UserDTO,然后转为 Map(需注意将所有字段转为 String 类型),以 Token 为 Key 存入 Redis 的 Hash 结构中,并设置一个较长的过期时间(如 30 分钟)。
  • 返回 Token: 将生成的 Token 字符串返回给前端,前端后续的请求都会在 Header 中携带这个 Token。

3. 校验登录状态与会话保持 (双拦截器机制)

这部分解决了用户活跃状态下的“自动续期”问题。

  • 全局刷新拦截器 (RefreshTokenInterceptor): 拦截所有路径 (/**)。尝试从请求头获取 Token,去 Redis 中查询对应的用户信息。如果查到了,将用户存入 ThreadLocal(方便后续业务使用),并刷新该 Token 在 Redis 中的有效期
  • 登录校验拦截器 (LoginInterceptor): 拦截需要登录权限的特定路径。它的逻辑非常简单,只需要检查 ThreadLocal 中是否有用户即可。如果没有,直接拦截并返回 401 状态码;如果有,直接放行。

📝 重点难点复习提醒

  • Redis 存储类型的选择: 验证码用 String(简单临时),用户信息用 Hash(节约内存,支持单字段修改)。
  • 序列化坑点: 使用 StringRedisTemplate 存储 Hash 对象时,一定要记得将对象中的非字符串字段(如 Long 类型的 id)转换成 String,否则会报 ClassCastException(就是你刚刚踩过并修复的那个坑)。
  • ThreadLocal 内存泄漏: 拦截器处理完请求后,务必要在 afterCompletion 方法中调用 remove() 清除当前线程的数据。