基于 Redis 实现验证码登录
一、我的理解
- 基于 Session 实现验证码登录,集群环境下,多个 Tomcat 服务器 Session 共享。
- 基于 Redis 实现验证码登录,实现集群环境下,更新用户登录信息。
二、操作步骤














三、AI 的理解
你的理解是正确的。你准确地抓住了两种方案的核心目的:
- 基于 Session 的方案:其核心挑战与解决方案都围绕着如何让多个 Tomcat 服务器共享 Session 数据,以解决集群环境下的登录状态不一致问题。
- 基于 Redis 的方案:这是一种更现代和主流的 Token 架构,它利用 Redis 作为集中式存储来保存用户的登录信息(如用户ID、昵称等),并通过拦截器在每次请求时验证和更新(刷新)登录信息的有效期。
下面我将为你详细解析这两种方案的实现原理和区别。
🧩 方案一:基于 Session 的验证码登录与集群共享
这种方案是传统 Web 应用登录方式的延伸,核心在于将原本存储在单个 Tomcat 内存中的 Session 数据,迁移到一个所有 Tomcat 都能访问的"中央仓库"中。
单机环境下的流程
在未部署集群时,流程非常简单:
- 用户请求获取验证码,服务器生成验证码后,使用
session.setAttribute("code", code)将其存入当前 Tomcat 的内存中。 - 用户提交手机号和验证码进行登录,服务器从
session.getAttribute("code")取出验证码进行比对。 - 校验通过后,将用户信息也存入 Session,标记为登录状态。
集群环境下的问题
当部署了多个 Tomcat 服务器并由 Nginx 进行负载均衡时,问题就出现了:
- 第一次请求 :用户被分配到
Tomcat-1,验证码存入了Tomcat-1的内存。 - 第二次请求 :用户的登录请求被 Nginx 分发到了
Tomcat-2。由于Tomcat-2的内存中没有之前保存的验证码,导致校验失败。
这就是所谓的 Session 粘滞性问题。
解决方案:Redis 实现 Session 共享
业界最主流的解决方案就是使用 Redis 作为集中的 Session 存储器。
- 改造点 :将所有
session.setAttribute()和session.getAttribute()的操作,替换为对 Redis 的读写操作。 - 效果:无论用户的请求被分发到哪一台 Tomcat,它们都去同一个 Redis 服务器存取验证码和用户 Session 信息,从而实现了 Session 的共享。
✨ 方案二:基于 Redis 的 Token 登录与信息更新
这是一种更彻底的改造,它完全抛弃了传统的 Servlet Session 机制,采用了无状态的 Token 架构。这也是目前微服务和前后端分离项目中最常用的方式。
核心流程
-
登录认证:
- 用户提交手机号和验证码。
- 服务端从 Redis 中校验验证码(Key 为手机号)。
- 校验通过后,根据手机号查询或创建用户。
- 服务端生成一个全局唯一的随机字符串作为 Token (例如使用 UUID)。
- 将用户信息(如 ID、昵称等)转换为一个 Map,并以 Hash 结构存入 Redis,Key 为这个 Token(例如
login:token:{token}),同时设置一个过期时间(如 30 分钟)。 - 将这个 Token 返回给前端(通常放在响应体或 Cookie 中)。
-
后续请求与登录信息更新:
- 前端在之后的每一次请求中,都在请求头(如
Authorization)携带这个 Token。 - 服务端通过一个 拦截器 (Interceptor) 拦截所有需要登录的请求。
- 拦截器从请求头中获取 Token,然后去 Redis 中查询对应的用户信息。
- 如果查不到,说明未登录或登录已过期,直接返回 401 状态码。
- 如果能查到,则将用户信息保存到
ThreadLocal中,供本次请求的后续业务逻辑使用。 - 关键一步:更新登录信息 。在放行请求前,拦截器会调用
redisTemplate.expire(key, time)方法,刷新 Redis 中该 Token 键的过期时间。这就实现了你所说的"更新用户登录信息",即只要用户持续活跃,登录状态就会自动续期。
- 前端在之后的每一次请求中,都在请求头(如
📊 两种方案对比
| 对比维度 | 基于 Session 的共享方案 | 基于 Redis 的 Token 方案 |
|---|---|---|
| 核心思想 | 改造原有 Session,使其存储于外部 Redis。 | 完全放弃 Session,采用无状态的 Token 机制。 |
| 数据存储 | 仍保留 Session 概念,但数据在 Redis。 | 无 Session,用户数据以 Hash 形式存于 Redis。 |
| 客户端凭证 | JSESSIONID (通过 Cookie 传递)。 | 自定义 Token (通常在请求头传递)。 |
| 适用场景 | 传统服务端渲染项目改造。 | 前后端分离、微服务、移动端 App。 |
| 优点 | 对原有代码侵入性相对较小。 | 无状态、扩展性强、跨平台支持好。 |
总而言之,你的理解非常到位。第一种方案是为了解决 Session 在集群下的共享难题,而第二种方案则是一种更优的实践,它不仅解决了共享问题,还通过 Token 和拦截器实现了灵活的登录状态管理和自动续期。