Redis实战——验证码和Token的存储与管理
本文最后更新于:2 个月前
引言
随着互联网应用的快速发展,用户认证方式也在不断演进。传统的用户名密码登录方式虽然广泛使用,但存在密码泄露、暴力破解等安全隐患。基于验证码的登录方式,尤其是通过邮箱验证码进行登录,因其操作简便、安全性高而受到越来越多应用的青睐。
在微服务架构下,多个服务协同工作,用户认证与授权需要具备高可用性和可扩展性。Redis作为高性能的内存数据存储系统,凭借其快速的数据读写能力和丰富的数据结构,成为实现分布式认证系统的理想选择。
本文将详细介绍如何在微服务架构中使用Redis实现邮箱验证码登录系统,包括各个流程的具体步骤、代码实现以及相关的优化建议。
发送邮箱验证码流程
步骤
- 客户端填写邮箱并提交至服务端。
- 服务端校验邮箱是否合法,不合法则提示客户端重新输入,合法则继续以下步骤。
- 判断邮箱是否有未过期的登录验证码,有则提示客户端勿频繁请求,无则继续以下步骤。
- 服务端生成多位数的随机验证码。
- 将邮箱与验证码的对应关系存入Redis中,并设置一定的过期时间。
- 异步地将验证码发送至对应的邮箱中,并进行日志记录与监控。
时序图
sequenceDiagram
participant 客户端
participant 服务端
participant Redis
participant 邮件服务
participant 日志系统
客户端->>服务端: 提交邮箱
服务端->>服务端: 校验邮箱合法性
alt 邮箱不合法
服务端->>客户端: 提示重新输入
else 邮箱合法
服务端->>Redis: 检查是否有未过期的验证码
alt 存在未过期的验证码
服务端->>客户端: 提示勿频繁请求
else 无未过期验证码
服务端->>服务端: 生成验证码
服务端->>Redis: 存储邮箱与验证码关系并设置过期时间
服务端->>邮件服务: 异步发送验证码
服务端->>日志系统: 记录日志与监控
服务端->>客户端: 验证码发送成功提示
end
end
代码示例
1 |
|
邮箱验证码登录流程
步骤
- 客户端填写邮箱及收到的验证码并提交至服务端。
- 服务端校验邮箱是否合法,不合法提示客户端重新输入,合法则继续以下步骤。
- 同一邮箱验证多次不通过以后应当限制该邮箱的登录操作。
- 校验邮箱与验证码的对应关系是否存在于Redis中,不存在则提示客户端重新输入、增加失败次数,存在则继续以下步骤。
- 根据邮箱查找用户是否存在,不存在则先创建用户。
- 生成Token并将Token与用户对象的对应关系存入Redis中,注意设置合理的过期时间。
- 将校验通过地邮箱验证码对应关系进行删除,防止重复使用。
- 返回Token至客户端。
时序图
sequenceDiagram
participant 客户端
participant 服务端
participant Redis
participant 用户数据库
客户端->>服务端: 提交邮箱和验证码
服务端->>服务端: 校验邮箱合法性
alt 邮箱不合法
服务端->>客户端: 提示重新输入
else 邮箱合法
服务端->>Redis: 检查该邮箱的登录尝试次数
alt 验证次数过多
服务端->>客户端: 限制登录操作
else 验证次数正常
服务端->>Redis: 校验邮箱与验证码的对应关系
alt 校验失败
服务端->>客户端: 提示重新输入
else 校验成功
服务端->>用户数据库: 根据邮箱查找用户
alt 用户不存在
服务端->>用户数据库: 创建新用户
end
服务端->>服务端: 生成Token
服务端->>Redis: 存储Token与用户的对应关系并设置过期时间
服务端->>Redis: 删除邮箱与验证码的对应关系
服务端->>客户端: 返回Token
客户端->>客户端: 本地存储Token值
end
end
end
代码示例
1 |
|
用户登录后的请求流程
步骤
- 设置拦截器获取请求头中authorization字段的Token值(注意拦截器应对注册、登录、请求验证码等接口放行)。
- 若Token值为空则响应401,否则对请求放行。
- 根据Token值从Redis中取出对应的用户对象,若用户对象为空,则响应401,否则继续放行。
- 将Token值对应的用户对象存入ThreadLocal中,方便后续流程使用。
- 刷新此Redis中此Token值的过期时间。
- 放行请求。
- 注意请求处理结束以后需及时清理ThreadLocal中的用户数据,避免内存泄漏。
时序图
sequenceDiagram
participant 客户端
participant 服务端
participant Redis
客户端->>服务端: 发送请求(带Token)
服务端->>服务端: 拦截器获取请求头中的Token值
alt Token为空
服务端->>客户端: 返回401响应
else Token不为空
服务端->>Redis: 根据Token从Redis获取用户对象
alt 用户对象为空
服务端->>客户端: 返回401响应
else 用户对象存在
服务端->>服务端: 往ThreadLocal存入用户对象
服务端->>Redis: 刷新Token的过期时间
服务端->>服务端: 放行请求
服务端->>服务端: 处理请求
服务端->>服务端: 请求结束,清理ThreadLocal中的用户数据
end
end
代码示例
用户信息存取工具类
1 |
|
登录拦截器
1 |
|
Token有效期刷新拦截器
1 |
|
Spring Boot拦截器配置
1 |
|
用户登出流程
步骤
- 获取请求头Token值,校验Token合法性,若不合法则返回错误信息,合法则继续。
- 删除Redis中Token值对应的键值对数据。
注意:
- Token的多设备支持,应根据业务要求决定是否允许单一Token多设备登录,或者为每个设备生成独立的Token。登出时,可以选择删除单个Token或所有相关Token。
- 确保客户端在登出后,清理本地存储的Token,防止意外的会话恢复。
时序图
sequenceDiagram
participant 客户端
participant 服务端
participant Redis
客户端->>服务端: 发送登出请求(带Token)
服务端->>服务端: 获取请求头中的Token值
alt Token不合法
服务端->>客户端: 返回错误信息
else Token合法
服务端->>Redis: 删除Token对应的键值对数据
服务端->>服务端: 删除ThreadLocal中的用户信息
服务端->>客户端: 返回登出成功消息
客户端->>客户端: 删除本地存取的Token值
end
代码示例
1 |
|
后续优化
- 单点故障:Redis作为核心组件,若出现故障可能影响整个认证系统的可用性。需通过Redis集群、高可用配置等手段提升系统的可靠性。
- 内存消耗:验证码和Token的存储依赖于Redis的内存,若用户量过大,可能导致Redis内存消耗迅速增加。需合理设置数据的过期时间,并进行内存监控和管理。
- 复杂的异常处理:在高并发和分布式环境下,验证码和Token的管理涉及多种异常情况(如Redis连接异常、网络延迟等),需要细致的异常处理和恢复机制。
- Token管理的复杂性:若采用传统的Opaque Token,需要在每次请求时访问Redis进行Token验证,可能成为性能瓶颈。可考虑使用JWT等无状态Token机制,但需权衡安全性和管理复杂性。
总结
本文详细介绍了如何在微服务架构下使用Redis实现基于邮箱验证码的登录系统,包括发送验证码、登录验证、Token管理以及登出流程。通过具体的步骤、时序图和代码示例,展示了系统的实现过程,并提出了多项优化建议,提升系统的性能、安全性和可维护性。
Redis凭借其高性能和丰富的数据结构,成为分布式认证系统中不可或缺的组件。然而,系统设计需充分考虑Redis的高可用性、内存管理以及异常处理,确保系统在高并发和分布式环境下的稳定性和可靠性。
在实际应用中,还可结合其他技术和策略,如使用消息队列进行异步处理、引入分布式锁防止并发冲突、采用无状态的JWT Token机制以减少对Redis的依赖等,进一步优化系统性能和用户体验。
通过合理的设计和优化,基于Redis的邮箱验证码登录系统能够在微服务架构中高效、安全地完成用户认证与授权,满足现代互联网应用的需求。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!