基于 Redis 的分布式登录系统实现总结

一、整体架构概述

这是一个基于 Spring Boot + Redis 的分布式登录系统,采用 Token 认证机制 ,实现了无状态的分布式会话管理。

核心技术栈

-**Spring Boot :Web 框架

  • Redis :分布式缓存,存储验证码和用户会话
  • MyBatis-Plus :数据库操作
  • Hutool :工具类库
  • Spring MVC 拦截器 :请求拦截和身份验证**

二、核心组件分析

1. LoginInterceptor(登录拦截器)

功能职责:

public class LoginInterceptor implements HandlerInterceptor

**- 身份验证 :验证请求是否携带有效的 token

  • 用户信息恢复 :从 Redis 获取用户信息
  • 会话刷新 :延长 token 有效期
  • ThreadLocal 存储 :将用户信息存储到线程本地变量 工作流程**

请求到达 → 获取 token → 验证 token → 恢复用户信息 → 刷新有效期 →

放行/拦截

关键代码解析

1. Token 获取与验证

String token = request.getHeader("authorization");

if (StrUtil.isBlank(token)) {

response.setStatus(401);

return false;

}

  • 从请求头获取 authorization 字段

  • 如果 token 不存在,返回 401 状态码

  • 前端需要将 token 添加到请求头

2. Redis 用户信息查询

String key = RedisConstants.LOGIN_USER_KEY + token;

Map<Object, Object> userMap = stringRedisTemplate.

opsForHash().entries(key);

if (userMap == null) {

response.setStatus(401);

return false;

}

  • 根据 token 构建 Redis 键

  • 使用 Hash 结构存储用户信息

  • 用户不存在则拦截请求

3. 用户信息转换与存储

UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new

UserDTO(), false);

UserHolder.saveUser(userDTO);

  • 将 Redis 中的 Map 数据转换为 UserDTO 对象

  • 存储到 ThreadLocal,方便后续业务使用

4. Token 有效期刷新

stringRedisTemplate.expire(key, RedisConstants.

LOGIN_USER_TTL, TimeUnit.MINUTES);

  • 刷新 token 有效期,实现滑动过期

  • 用户活跃时自动延长登录状态

2. sendCode 方法(验证码发送) 功能职责

  • 手机号验证 :校验手机号格式

  • 验证码生成 :生成 6 位随机验证码

  • Redis 存储 :将验证码存储到 Redis

  • 模拟发送 :后端模拟短信发送 关键代码解析

1. 手机号格式验证

if (RegexUtils.isPhoneInvalid(phone)) {

return Result.fail("手机号格式有误");

}

  • 使用正则表达式验证手机号格式

  • 格式错误直接返回失败信息

2. 验证码生成与存储

String code = RandomUtil.randomNumbers(6);

stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY +

phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

  • 生成 6 位数字验证码

  • 存储到 Redis,键为 login:code:手机号

  • 设置过期时间,通常 2-5 分钟

3. login 方法(用户登录) 功能职责

  • 手机号验证 :校验手机号格式

  • 验证码验证 :验证用户输入的验证码

  • 用户查询 :根据手机号查询用户信息

  • 用户创建 :新用户自动注册

  • Token 生成 :生成登录令牌并存储 关键代码解析

1. 验证码验证

String cacheCode = stringRedisTemplate.opsForValue().get

(LOGIN_CODE_KEY + phone);

String code = loginForm.getCode();

if (cacheCode == null || !cacheCode.equals(code)) {

return Result.fail("验证码错误");

}

  • 从 Redis 获取存储的验证码

  • 验证验证码是否正确或已过期

  • 验证失败返回错误信息

2. 用户查询与创建

User user = query().eq("phone", phone).one();

if (user == null) {

user = createUserWithPhone(phone);

}

  • 使用 MyBatis-Plus 查询用户

  • 用户不存在时自动创建新用户

  • 实现手机号即账号的登录方式

3. Token 生成与存储

String token = UUID.randomUUID().toString();

UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.

class);

Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,

new HashMap<>(), CopyOptions.create()

.setIgnoreNullValue(true)

.setFieldValueEditor((fieldName, fieldValue) ->

fieldValue.toString()));

String tokenKey = LOGIN_USER_KEY + token;

stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);

stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL,

TimeUnit.MINUTES);

  • 生成唯一 token

  • 转换用户对象为 Map 格式

  • 存储到 Redis Hash 结构

  • 设置 token 有效期

4. 拦截器配置

功能职责:

  • 登录拦截器 :验证用户登录状态

  • Token 刷新拦截器 :自动刷新 token 有效期

  • 路径排除 :配置不需要登录的路径 关键代码解析

registry.addInterceptor(new LoginInterceptor

(stringRedisTemplate))

.excludePathPatterns(

"/shop/**",

"/voucher/**",

"/shop-type/**",

"/upload/**",

"/blog/hot",

"/user/code",

"/user/login"

).order(1);

registry.addInterceptor(new RefreshTokenInterceptor

(stringRedisTemplate))

.addPathPatterns("/**").order(0);

拦截器执行顺序

  1. Token 刷新拦截器(order=0) :优先执行,刷新 token 有效期

  2. 登录拦截器(order=1) :验证用户登录状态

排除路径配置

  • 公开接口:商品、优惠券、上传等

  • 登录相关接口:验证码、登录接口

三、技术亮点与优势

1. 分布式支持

  • Redis 存储 :支持多服务器共享登录状态

  • 无状态设计 :服务器可以水平扩展

  • 负载均衡友好 :无需会话粘性

2. 安全性设计

  • Token 随机生成 :UUID 确保唯一性

  • 验证码时效性 :自动过期,防止重放攻击

  • 请求头认证 :避免 token 泄露到 URL

3. 用户体验优化

  • 滑动过期 :活跃用户自动延长登录状态

  • 自动注册 :手机号即账号,降低注册门槛

  • 拦截器透明 :业务代码无需关心认证逻辑

4. 性能优化

  • Redis 缓存 :减少数据库查询

  • ThreadLocal 存储 :避免重复查询用户信息

  • Hash 结构 :高效存储和查询用户数据

四、完整登录流程

  1. 用户请求验证码

  1. 后端生成验证码并存储到 Redis

  1. 用户输入验证码并登录

  1. 后端验证验证码

  1. 查询/创建用户信息

  1. 生成 Token 并存储到 Redis

  1. 返回 Token 给前端

  1. 前端存储 Token

  1. 后续请求携带 Token

  1. 拦截器验证 Token 并刷新有效期
相关推荐
2603_9651481112 小时前
如何解析JSON数据?API返回的商品信息处理教程
开发语言·数据库·python·自动化·json·api
ltl12 小时前
RocksDB 经典故障排查:L0、compaction 与 write stall
数据库
ltl12 小时前
2PC 的真实失败模式:阻塞、脑裂与恢复
分布式
xfhuangfu13 小时前
Oracle中建立到CDB和PDB的连接
数据库·oracle·rpc
小小龙学IT13 小时前
DuckDB 深度实战:用 C++ 在进程内跑一个「分析型数据库」
数据库·c++
NineData13 小时前
DTCC 2026 预告|NineData CEO& 创始人叶正盛:面向 AI Agent 的数据库 DevOps 与数据复制实践
数据库·人工智能·数据库开发·devops·ninedata·数据库技术·dtcc
J_bean14 小时前
MySQL 事务是否必须手动开启?
数据库·mysql·数据库事务·自动提交·手动提交
J_bean14 小时前
MySQL InnoDB 如何检测死锁、判定死锁、处理死锁
数据库·mysql·死锁·死锁检测·处理死锁·死锁判定
霸道流氓气质14 小时前
分布式系统设计:技术解析与实践
分布式
浪子明X14 小时前
从 MongoDB 文档到关系模型:构建可重跑、可对账的数据迁移流水线
数据库·mongodb·oracle