基于 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 并刷新有效期
相关推荐
salipopl2 小时前
mysql数据被误删的恢复方案
数据库·mysql
Cc琎2 小时前
api接口分布在多台服务器, 如何同步用户的每日请求次数
java·运维·服务器·redis·php
数据知道2 小时前
MongoDB大数据文档设计:处理超过16MB文档的实用策略
数据库·mongodb
悦数图数据库4 小时前
图数据库如何重塑行业智能决策 | 破局金融数据关联困局 悦数图数据库
数据库·金融
2401_879693874 小时前
Python深度学习入门:TensorFlow 2.0/Keras实战
jvm·数据库·python
Nsequence5 小时前
图书馆-读者等级(附:MySQL)
数据库·mysql
知识分享小能手8 小时前
Redis入门学习教程,从入门到精通,Redis 概述:知识点详解(1)
数据库·redis·学习
xixihaha132410 小时前
将Python Web应用部署到服务器(Docker + Nginx)
jvm·数据库·python
夕除10 小时前
Mysql--07
数据库·mysql