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

借助Redis实现Token黑名单机制

1. 概述

如果没有为Token提供主动失效机制。一旦Token被签发,在过期之前将一直有效,存在以下安全隐患:

  1. 无法主动注销:用户注销后,已签发的Token仍然有效
  2. 安全风险:Token泄露后无法立即失效
  3. 缺乏控制:无法对特定Token进行精准控制

本博客通过将已失效的Token存储在Redis中,可以确保Token在被主动注销后无法继续使用,提高了系统的安全性和可控性。

2. 具体方案

2.1 设计思路

通过在Redis中维护一个Token黑名单来实现Token的主动失效功能:

  1. 当用户注销或Token需要主动失效时,将Token加入黑名单
  2. 在验证Token时,先检查是否在黑名单中
  3. 如果在黑名单中,则认为Token已失效

2.2 Redis存储设计

Key: token:blacklist:{token}
Value: "blacklisted"
Expire: Token剩余有效时间

2.3 TokenUtil中新增方法

2.3.1 addToBlacklist方法
/*** 将Token加入黑名单,实现主动失效** @param token JWT token* @return 是否成功加入黑名单*/
public boolean addToBlacklist(String token) {try {// 获取Token的过期时间Date expirationDate = getExpirationDateFromToken(token);if (expirationDate == null) {return false;}// 计算剩余有效时间long remainingTime = expirationDate.getTime() - System.currentTimeMillis();if (remainingTime <= 0) {return false;}// 将Token加入Redis黑名单,设置过期时间为Token剩余有效时间String key = TOKEN_BLACKLIST_PREFIX + token;return redisUtil.set(key, "blacklisted", remainingTime / 1000);} catch (Exception e) {return false;}
}
2.3.2 isTokenInBlacklist方法
/*** 检查Token是否在黑名单中** @param token JWT token* @return 是否在黑名单中*/
public boolean isTokenInBlacklist(String token) {String key = TOKEN_BLACKLIST_PREFIX + token;return redisUtil.exists(key);
}
2.3.3 removeFromBlacklist方法
/*** 从黑名单中移除Token** @param token JWT token* @return 是否成功移除*/
public boolean removeFromBlacklist(String token) {String key = TOKEN_BLACKLIST_PREFIX + token;return redisUtil.del(key) > 0;
}
2.3.4 修改validateToken方法
/*** 验证Token是否合法且未过期** @param token JWT token* * @return 是否有效*/
public Boolean validateToken(String token) {try {// 检查Token是否在黑名单中if (isTokenInBlacklist(token)) {return false;}JwtParser parser = Jwts.parser().verifyWith(secretKey).build();parser.parseSignedClaims(token);return true;} catch (JwtException e) {System.out.println("JWT exception: " + e.getMessage());} catch (IllegalArgumentException e) {System.out.println("JWT claims string is empty: " + e.getMessage());}return false;
}

3. 使用示例

3.1 用户注销时将Token加入黑名单

@PostMapping("/logout")
public ResultBean<String> logout(@RequestHeader("Authorization") String token) {if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);// 将Token加入黑名单boolean added = tokenUtil.addToBlacklist(token);if (added) {return ResultBean.success("注销成功");}}return ResultBean.error("注销失败");
}

3.2 在拦截器中验证Token

@Component
public class TokenInterceptor implements HandlerInterceptor {@Autowiredprivate TokenUtil tokenUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7);// 验证Token(会自动检查黑名单)if (!tokenUtil.validateToken(token)) {response.setStatus(HttpStatus.UNAUTHORIZED.value());return false;}}return true;}
}

3.3 管理员强制用户下线

@PostMapping("/admin/forceLogout")
public ResultBean<String> forceLogout(@RequestParam String token) {// 将Token加入黑名单boolean added = tokenUtil.addToBlacklist(token);if (added) {return ResultBean.success("用户已强制下线");}return ResultBean.error("操作失败");
}

4. 优化效果

4.1 安全性提升

  • 实现了Token的主动失效功能
  • 可以精准控制特定Token的可用性
  • 有效防止Token泄露后的安全风险

4.2 控制性增强

  • 提供了细粒度的Token控制能力
  • 支持用户主动注销和管理员强制下线
  • 可以根据业务需求灵活控制Token生命周期

4.3 用户体验改善

  • 用户注销后Token立即失效
  • 管理员可以强制用户下线
  • 提高了系统的安全性和可控性

5. 注意事项

  1. Redis性能: 黑名单存储在Redis中,需要注意Redis的性能和容量
  2. 过期时间: 黑名单中的Token会自动过期,过期时间与Token剩余有效时间一致
  3. 异常处理: 需要妥善处理Redis操作可能出现的异常
  4. 并发控制: 在高并发场景下需要注意Redis操作的并发控制
http://www.dtcms.com/a/573085.html

相关文章:

  • 缓存机制:Redis集成
  • 做网站要先申请域名吗搭建网站的英语
  • 优思学院|什么是5M1E?它是如何影响产品质量的?
  • 技术赋能生态保护:无人机RTMP推流平台EasyDSS在野生动植物监测中的应用实践
  • 大模型应用技术之提示词工程面试题(二)
  • 对比传统方法和深度学习方法在MATLAB视觉检测中的优缺点
  • 从容器化到自动化:Vue3 项目 Docker 部署与 GitLab CI/CD 集成 Harbor 全流程
  • 企业网站Wap在线生成格力网站建设首页
  • Hibernate 速览指南
  • 凡科网站建设步骤企业年金查询
  • AssertJ,让断言更流畅的Java测试库!
  • C++:大型语言模型与智能系统底座的隐形引擎
  • 你好,未来:零基础看懂大语言模型
  • Spring Boot 多线程文件复制服务(支持大文件流式/NIO复制、失败重试、覆盖写入)
  • 当视觉语言模型接收到相互矛盾的信息时,它会相信哪个信号?
  • 软考中级习题与解答——UML中主要关系
  • 公司做网站属于什么费用wordpress 加入页面
  • 以太网帧格式、IP数据报头部、TCP头部、UDP头部
  • CRMEB标准版小票打印功能详解
  • Java开发性能优化
  • 传输层最重要的两种协议——UDP与TCP的区别(TCP可靠但是慢,UDP不可靠但是快)
  • list(带头双向循环链表)
  • Linux的例行工作
  • Java List全面解析:从入门到精通
  • 英文网站如何做关键词怎样免费注册自己网站的域名
  • Win11卸载重装oracle 11g数据库
  • 模拟电路-工程实践-磁珠的使用方法
  • verilog中数据类型real
  • 如何选择适合的单北斗GNSS变形监测解决方案?
  • 使用vue获取url上的参数