当前位置: 首页 > news >正文

SpringBoot14-集成Redis

一、SpringBoot集成Redis


1-1、先理解:什么是 Redis?

Redis 就是一个超快的数据库,但它专门存 数据在内存(不是硬盘)。

你可以把它想象成:

一个超级快的“笔记本”,用来暂时记一些数据。
比如:登录状态、验证码、排行榜、购物车、点赞数……

为什么用 Redis?

因为它:

  • 速度非常快(比 MySQL 快几十~上百倍)

  • 可以自动过期(适合存验证码、token)

  • 可以解决并发问题(比如抢票、库存扣减)


1-2、第一步:安装 Redis

(1)如果你用 Windows

下载 Redis for Windows(无需安装)

https://github.com/tporadowski/redis/releases

打开 redis-server.exe 就启动了。

(2)如果是 Mac

brew install redis
brew services start redis

启动成功后,Redis 会在 6379 端口上运行。

(3)验证是否安装了redis:


1-3、第二步:在 Spring Boot 项目中加依赖

pom.xml 加:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

就这样,Redis 支持就进项目了。


1-4、第三步:配置连接 Redis

application.yml 里写:

spring:data:redis:host: 127.0.0.1  # 本机port: 6379       # 默认端口

如果你 Redis 设置了密码,这里再加 password: xxx


1-5、第四步:写一个最简单的 Redis 代码(存 + 取)

1、写一个 Service 类:

@Service
public class RedisTestService {@Autowiredprivate StringRedisTemplate stringRedisTemplate; // 专门操作字符串// 存数据public void saveData() {stringRedisTemplate.opsForValue().set("name", "Tom");}// 取数据public String getData() {return stringRedisTemplate.opsForValue().get("name");}
}

Maven中添加了redis的依赖之后,StringRedisTemplate就能直接注入使用了!


2、写个 Controller 调用它

@RestController
public class TestController {@Autowiredprivate RedisTestService redisTestService;@GetMapping("/save")public String save() {redisTestService.saveData();return "保存成功!";}@GetMapping("/get")public String get() {return redisTestService.getData();}
}

3、运行测试

浏览器访问:

① 保存数据:

http://localhost:8080/save

② 获取数据:

http://localhost:8080/get

你将看到返回:

Tom

你已经成功用 Spring Boot 操作 Redis 了!


4、或者直接写一个redis的测试类

1-6、小结

二、令牌主动失效

目标:

  1. 登录成功 → 把发给浏览器的令牌同时存进 Redis;

  2. 每次请求在拦截器里比对“浏览器带来的令牌 == Redis里为该用户保存的令牌”;

  3. 用户改密成功 → 主动删除 Redis 里的旧令牌,使其立刻失效。


2-1、Redis 存储设计(双向映射,便于比对和失效)

  • auth:user:{userId} -> {token}用户当前有效 token,便于改密时一把踢下线)

  • auth:token:{token} -> {userId}用 token 找到用户,拦截器校验时用)

两个 key 都设置相同 TTL(比如 2 小时);再次登录会覆盖旧 token。


2-2、登录:生成并落库(含顶替旧令牌)

@Service
@RequiredArgsConstructor
public class AuthService {private final StringRedisTemplate redis;// 令牌有效期private static final long TOKEN_TTL_MINUTES = 120;public String login(Long userId, String rawPassword) {// 1. 这里省略账号密码校验(查库比对哈希)// if (!passOK) throw new BizException(...);// 2. 生成新 tokenString token = UUID.randomUUID().toString();// 3. 顶替旧 token(如果有就删)String oldToken = redis.opsForValue().get("auth:user:" + userId);if (oldToken != null) {redis.delete("auth:token:" + oldToken);}// 4. 双向写入 + 过期时间redis.opsForValue().set("auth:user:" + userId, token, TOKEN_TTL_MINUTES, TimeUnit.MINUTES);redis.opsForValue().set("auth:token:" + token, String.valueOf(userId), TOKEN_TTL_MINUTES, TimeUnit.MINUTES);// 5. 返回给前端return token;}// 退出登录:前端丢弃 + 服务端删除public void logout(String token) {if (token == null) return;String userId = redis.opsForValue().get("auth:token:" + token);if (userId != null) {redis.delete("auth:token:" + token);redis.delete("auth:user:" + userId);}}// 改密后:让旧令牌立即失效(主动删除)public void invalidateUserTokenOnPasswordChange(Long userId) {String oldToken = redis.opsForValue().get("auth:user:" + userId);if (oldToken != null) {redis.delete("auth:user:" + userId);redis.delete("auth:token:" + oldToken);}}
}

示例 Controller(返回 token 给前端;退出;改密后失效):

@RestController
@RequiredArgsConstructor
public class AuthController {private final AuthService authService;@PostMapping("/login")public String login(@RequestParam Long userId, @RequestParam String password) {return authService.login(userId, password);}@PostMapping("/logout")public void logout(@RequestHeader("Authorization") String token) {authService.logout(token);}// 改密成功后调用:旧 token 立刻失效@PostMapping("/password/change")public String changePwd(@RequestParam Long userId,@RequestParam String oldPwd,@RequestParam String newPwd) {// 1) 校验旧密码并更新为新密码(略)// 2) 主动失效旧令牌authService.invalidateUserTokenOnPasswordChange(userId);// 3) 可选:直接让用户重新登录,或这里返回新 tokenreturn "OK";}
}

2-3、拦截器校验:比对“请求令牌 == Redis 存的令牌”

@Component
@RequiredArgsConstructor
public class LoginInterceptor implements HandlerInterceptor {private final StringRedisTemplate redis;@Overridepublic boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {String token = req.getHeader("Authorization");if (token == null || token.isEmpty()) {resp.setStatus(401);return false;}// 1) 通过 token 找 userId(无则说明 token 无效或过期)String userId = redis.opsForValue().get("auth:token:" + token);if (userId == null) {resp.setStatus(401);return false;}// 2) 再用 userId 取当前有效 token,必须“完全相等”才算有效String currentToken = redis.opsForValue().get("auth:user:" + userId);if (!token.equals(currentToken)) {// 出现这种情况:用户在别处重新登录/改了密码/已被踢下线resp.setStatus(401);return false;}// ✅ 校验通过return true;}
}

注册拦截器:

@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {private final LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/login"); // 登录接口放行}
}

2-4、前端怎么带令牌

  • 登录后保存服务端返回的 token

  • 之后每个请求都在请求头带上:

Authorization: <token>

(名字可自定义,统一即可)


2-5、可选增强

  1. 自动续期(活跃会话不掉线)
    在拦截器校验通过后,给两个 key 续命(重置 TTL):

// 校验通过后
redis.expire("auth:token:" + token, 120, TimeUnit.MINUTES);
redis.expire("auth:user:" + userId, 120, TimeUnit.MINUTES);
  1. 单设备登录
    上面的“顶替旧令牌”已经实现了单设备登录——新登录会让旧 token 失效。

  2. 多端共存
    auth:user:{userId} 改成 Set,允许保存多个 token(PC/手机各一个);
    改密时删除该用户所有 token。

http://www.dtcms.com/a/545679.html

相关文章:

  • Maven 下载和 Spring Boot 搭建
  • 怎么花最少的钱做网站上海建设工程招标网
  • 分布式锁Redis、ZooKeeper 和数据库实现分布式锁的优缺点、实现方式以及适用场景
  • 《创作一周年有感》
  • Rust:异步锁(Mutex、RwLock)的设计
  • EG1195S 带使能降压开关电源控制芯片技术解析
  • 关于解决stm32cubeIDE打开现有工程失败的方法:
  • 代码随想录 669.修剪二叉搜索树
  • 单细胞转录组测序上游——cellranger
  • 下模板做网站阿里巴巴网页版
  • 组态软件SCADA在化工行业的应用
  • 移动商城 网站建设方法方式无锡做网站专业的公司
  • seo网站推广教程网红营销策略
  • 《考研408数据结构》第六章(5.5树的应用)复习笔记
  • 关于电子商务网站建设的论文飞飞影视做的网站
  • MiniMax-M2 在SCNet超算平台尝鲜(4卡不够,未完成)
  • Java 基本数据类型详解:从理论到实践
  • 自建大模型推理引擎中 KV Cache 的有效设计
  • 0010.static修饰的全局变量被无意间修改
  • 误入网站退不了怎么做制作音乐排行榜网页设计
  • 前端低代码开发实践:配置驱动与可视化搭建
  • godot4.4 如何让游戏画面没有透视【正交相机】
  • 电子商务平台 网站 建设方式Wordpress游戏rpg
  • 仓颉语言中Channel通道的深度解析:从原理到高并发实践
  • 数据网站建设多少钱重庆平台网站建设工作
  • 企业网站管理系统使用教程微信小程序开发文档下载
  • MATLAB复杂曲线曲面造型及导函数实现
  • OpenAI首发AI浏览器,互联网流量格局如何重塑
  • 【1.3】costas环的MATLAB仿真与测试
  • 使用FormData上传图片和JSON数据注意事项