基于 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 并刷新有效期
相关推荐
一直都在57214 小时前
MySQL索引优化
android·数据库·mysql
wjp@00114 小时前
SQL server导出导入数据
运维·服务器·数据库
脑子加油站14 小时前
MySQL8数据库高级特性
数据库·mysql
REDcker14 小时前
OpenSSL:C 语言 TLS 客户端完整示例
c语言·网络·数据库
zly350015 小时前
centos7 mysql 无法被远程连接
数据库·mysql
廿一夏15 小时前
MySql的增删改查
数据库·mysql·dba
瀚高PG实验室15 小时前
HGDB 4.5.8.8开启oracle兼容执行带聚合函数的SQL导致数据库进程被信号11杀死
数据库·sql·oracle·瀚高数据库
炘爚15 小时前
日志系统整体设计步骤以及功能函数梳理
运维·服务器·数据库
_下雨天.15 小时前
PostgreSQL日常维护
数据库·postgresql
神の愛15 小时前
本地连接MySql数据库报错??
数据库·mysql