基于 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 并刷新有效期
相关推荐
Mr.朱鹏32 分钟前
Linux 服务器 LVM 根分区在线动态扩容
linux·服务器·数据库
摇滚侠34 分钟前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 数据库初始化机制 阅读笔记 36
数据库·spring boot·笔记
qiuhaipeng140 分钟前
Claude code 升级后上下文长度变短问题
java·前端·数据库
wxwx_bscxy3221 小时前
基于Python新冠疫情可视化分析系统的设计与实现
java·数据库·spring boot·python·微信小程序·sqlite
剑之所向2 小时前
.NET 官方`System.Threading.Channels`
前端·javascript·数据库
词却3 小时前
数据库基础:DQL 数据查询语言
数据库·oracle
昌原的儿子LEO5 小时前
Linux IO多路复用与SQLite数据库核心知识点总结
linux·数据库·oracle
山岚的运维笔记5 小时前
mysql 专业笔记 -- 第 8 章:使用变量
运维·数据库·笔记·后端·学习·mysql·dba
聚美智数5 小时前
网安查询-备案查询-网络安全查询API接口介绍
网络·数据库·web安全
坐吃山猪6 小时前
【多线程】Semaphore使用
java·数据库·oracle·多线程