双 Token 三验证解决方案

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验


问题分析


以往的项目大部分解决方案为单 token:

  • 用户登录后,服务端颁发 jwt 令牌作为 token 返回
  • 每次请求,前端携带 token 访问,服务端解析 token 进行校验和鉴权

存在的问题:

  • 有效期设置问题:有效期设置需要对时间做平衡,不能太短也不能太长
  • 续期问题:一旦过期,用户必须重新登录,很难做无感刷新
  • 无状态问题:token 是无状态的,单 token 颁发后服务端无法主动使其失效

原理解析


这里引入双 token 机制:

  • accessToken:时间较短,一般为 5 分钟或者更短
  • refreshToken:时间较长,一般为 1 到 3 天

登录过程:

  • 用户携带用户名和密码登录
  • 服务端为其颁发 accessToken 和 refreshToken

三验证环节:

  • 一验证:前端请求携带 accessToken,验证是否过期,不过期放行,过期则进入第二个验证环节
  • 二验证:前端请求携带 refreshToken,验证是否过期,不过期进入第三个验证环节,过期则要求用户重新登录
  • 三验证:在 redis 种验证 refreshToken 是否存在,存在则颁发新的 accessToken 和 refreshToken 返回前端更新,将原来的 refreshToken 删除,再把新的 refreshToken 存入 redis

该机制的 UML 图如下:


最佳实践


生成 Token


基于 SpringCache 来操作 redis,利用 MD5 算法对 token 进行加密,防止其作为键的后缀存入时过长,导致”大KEY“的问题出现

public class CommonRedisConstants {public static class RedisKey {/*** refreshToken 前缀*/public static final String REFRESH_TOKEN_PREFIX = "REFRESH_TOKEN_PREFIX_%s";}
}
@Resource
private StringRedisTemplate stringRedisTemplate;// 生成 accessToken
private String createAccessToken(Map<String, Object> claims) {// 这里是利用 jjwt 编写的工具类方法,读者可以自行实现相关工具类return JwtUtils.generateAccessToken(claims);
}// 生成 refreshToken 并存入 redis
private String createRefreshToken(Map<String, Object> claims) {String refreshToken = JwtUtils.generateRefreshToken(claims);// redisKey 的形式为固定前缀+md5转换的tokenString redisKey = String.format(CommonRedisConstants.RedisKey.REFRESH_TOKEN_PREFIX, MD5Util.generateMd5Str(refreshToken));// 设置有效期为 3 daysthis.stringRedisTemplate.opsForValue().set(redisKey, refreshToken, Duration.ofDays(3L));return refreshToken;
}

校验 Token


基于自定义注解和 Spring AOP 实现校验 token,并将解析后的信息存储到上下文

自定义的注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentUser {
}

AOP 切面:

@Aspect
@Component
@Slf4j
public class CurrentUserAspect {private final HttpServletRequest request;public CurrentUserAspect(HttpServletRequest request) {this.request = request;}@Before("@annotation(currentUser)")public void setUserContext(CurrentUser currentUser) {String token = request.getHeader("Authorization");if (token != null) {try {// 这里是利用 jjwt 编写的工具类方法,读者可以自行实现相关工具类Claims claims = JwtUtils.parseToken(token);// 这里是利用 ThreadLocal 存储用户信息到上下文,读者可以自行实现相关工具类UserContextUtil.set(claims);} catch (Exception e) {// token 解析失败后的逻辑}} else {// 请求头未携带 token 的逻辑}}// 方法执行完后释放资源,防止内存泄漏@After("@annotation(currentUser)")public void clearUserContext(CurrentUser currentUser) {UserContextUtil.clear();}}

刷新 Token


前端调用刷新 token 后,服务端返回新的 accessToken 和 refreshToken:

@Data
@AllArgsConstructor
public class AdminLoginVO {private String accessToken;private String refreshToken;
}
public AdminLoginVO refreshLogin(String refreshToken) {// 校验 token 是否有效boolean isValidated = JwtUtils.validateToken(refreshToken);if (!isValidated) {// token }/*** 校验 redis 里的 refreshToken 是否失效* 未失效:将 redis 里的 refreshToken 删除,重新颁发新的 accessToken 和 refreshToken* 已失效:重新登录*/String redisKey = String.format(CommonRedisConstants.RedisKey.REFRESH_TOKEN_PREFIX, MD5Util.generateMd5Str(JwtUtils.preDecodeToken(refreshToken)));Boolean hasKey = this.stringRedisTemplate.hasKey(redisKey);if (ObjectUtil.notEqual(hasKey, Boolean.TRUE)) {// 原 token 过期或已经使用过的逻辑}// 删除原 tokenthis.stringRedisTemplate.delete(redisKey);// 颁发新的 accessToken 和 refreshTokenClaims claims = JwtUtils.parseToken(refreshToken);String accessToken = createAccessToken(claims);refreshToken = createRefreshToken(claims);return new AdminLoginVO(accessToken, refreshToken);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/389293.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu配置项目环境

目录 一、Xshell连接云服务器 二、切换到root用户 三、安装jdk 四、安装tomcat 五、安装mysql 1、安装mysql服务器 2、卸载mysql服务器 六、正式进行程序的部署 一、Xshell连接云服务器 要想使用xshell连接上云服务器就需要明确云服务器的几个信息&#xff1a; 1&…

科研绘图系列:R语言GWAS曼哈顿图(Manhattan plot)

介绍 曼哈顿图(Manhattan Plot)是一种常用于展示全基因组关联研究(Genome-Wide Association Study, GWAS)结果的图形。GWAS是一种研究方法,用于识别整个基因组中与特定疾病或性状相关的遗传变异。 特点: 染色体表示:曼哈顿图通常将每个染色体表示为一个水平条,染色体…

tarojs项目启动篇

TaroJS 是一个开放式跨端开发解决方案&#xff0c;使用 React 语法规范来开发多端应用&#xff08;包括小程序、H5、React Native 等&#xff09;。它可以帮助开发者高效地构建出在不同端上运行一致的应用。以下是启动 TaroJS 项目&#xff08;本来就有的旧项目&#xff09;的步…

⭐️2024年7月全球排名前二十开发语言全面对比横向竖向PK(TIOBE指数榜单)编程语言介绍 适用场景 优势 举例 详细说明 编写第一个语言程序Hello world源代码

2024年7月全球排名前二十开发语言全面对比横向竖向PK&#xff08;TIOBE指数榜单&#xff09;编程语言介绍 适用场景 优势 举例 详细说明 编写第一个语言程序Hello world源代码 2024年7月全球排名前二十开发语言全面对比横向竖向PK&#xff08;TIOBE指数榜单&#xff09;编程语言…

反序列化靶机serial

1.创建虚拟机 2.渗透测试过程 探测主机存活&#xff08;目标主机IP地址&#xff09; 使用nmap探测主机存活或者使用Kali里的netdicover进行探测 -PS/-PA/-PU/-PY:这些参数即可以探测主机存活&#xff0c;也可以同时进行端口扫描。&#xff08;例如&#xff1a;-PS&#xff0…

【python】Python中采集Prometheus数据,进行数据分析和可视化展示

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

如何在 Debian 上安装运行极狐GitLab Runner?【二】

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门面向中国程序员和企业提供企业级一体化 DevOps 平台&#xff0c;用来帮助用户实现需求管理、源代码托管、CI/CD、安全合规&#xff0c;而且所有的操作都是在一个平台上进行&#xff0c;省事省心省钱。可以一键安装极狐GitL…

本地生活服务商公司有哪些?一文教你搭建本地生活系统!

当前&#xff0c;本地生活领域群雄环伺&#xff0c;日益激烈的竞争推动各家互联网大厂调整布局模式的同时&#xff0c;也让本地生活市场持续迸发新的活力。在此背景下&#xff0c;想要通过本地生活服务商身份入局的创业者数量不断增多&#xff0c;以本地生活服务商公司有哪些等…

BEVGPT展示自动驾驶的“全知视角”,预测决策规划三合一的革新之作!

前言 本篇文章由原paper一作Pengqin Wang&#xff08;王鹏钦&#xff09;全权翻译分享&#xff0c;王鹏钦为香港科技大学博士生&#xff0c;师从沈劭劼教授、朱美新教授。他的研究方向为自动驾驶和机器人系统中的决策、预测和规划。他的研究成果发表于TMECH、RAL、IROS、TRB等…

互联网政务应用安全管理规定

互联网政务应用安全管理规定 &#xff08;2024年2月19日中央网络安全和信息化委员会办公室、中央机构编制委员会办公室、工业和信息化部、公安部制定 2024年5月15日发布&#xff09; 第一章 总则 第一条为保障互联网政务应用安全&#xff0c;根据《中华人民共和国网络安全法…

【前端新手小白】学习Javascript的【开源好项目】推荐

目录 前言 1 项目介绍 1.1 时间日期类 1.2 网页store类 1.3 事件类 1.4 Number类 1.5 String类 1.6 正则验证类 1.7 ajax类 1.8 data数据类 1.9 browser浏览器类 2 学习js-tool-big-box开源项目时有哪些收获 2.1 你可以这样做 2.2 如果你需要使用本项目 2.3 你…

内网穿透的应用-Windows系统如何ssh连接群晖nas使用docker安装内网穿透软件

文章目录 前言1. 检查安装Container Manager2. 检查开启群晖SSH连接3. Windows SSH 连接群晖4. 下载Cpolar 镜像5. 群晖Docker安装Cpolar 前言 在某些群晖NAS型号版本&#xff0c;无法使用套件安装的时候&#xff0c;我们可以采用Docker的方式进行安装cpolar内网穿透工具&…

MySQL:Prepared Statement 预处理语句

预处理语句&#xff08;Prepared Statement&#xff09; 是一种在数据库管理系统中使用的编程概念&#xff0c;用于执行对数据库进行操作的 SQL 语句。 使用预处理语句的具体方式和语法依赖于所用的编程语言和数据库管理系统。常见的编程语言如 Java、PHP、Python 和 C# 都提供…

CNN卷积网络实现MNIST数据集手写数字识别

步骤一&#xff1a;加载MNIST数据集 train_data MNIST(root./data,trainTrue,downloadFalse,transformtransforms.ToTensor()) train_loader DataLoader(train_data,shuffleTrue,batch_size64) # 测试数据集 test_data MNIST(root./data,trainFalse,downloadFalse,transfor…

GBase8c psycopg2安装(centos6)

GBase8c psycopg2安装(centos6) 安装步骤&#xff1a; [rootcentos6 ~]# cd /opt/python/ [rootcentos6 python]# ls psycopg2-2.7.7.tar.gz [rootcentos6 python]# tar -zxf psycopg2-2.7.7.tar.gz [rootcentos6 python]# cd psycopg2-2.7.7 # 安装命令 [rootcentos6 psycop…

B站安全开发流程落地实践

一. 什么是安全开发生命周期&#xff08;SDL&#xff09; 1.1 SDL诞生背景 随着互联网技术的快速发展&#xff0c;网络系统及应用在给人们的生活带来巨大便利的同时&#xff0c;信息安全问题也逐渐成为用户和企业关注的焦点。然而&#xff0c;安全问题的管理和解决需要一个系统…

武汉流星汇聚:亚马逊Prime会员日后,确保持续稳定出单的五大策略

随着亚马逊Prime会员日的圆满落幕&#xff0c;无数商家沉浸在销售高峰的喜悦之中&#xff0c;但狂欢之后的冷静思考同样重要。对于所有卖家而言&#xff0c;如何在会员日热潮退去后&#xff0c;依然保持稳定的订单量&#xff0c;成为关乎长远发展的关键。以下&#xff0c;武汉流…

MySQL数据库入门基础知识 【1】推荐

数据库就是储存和管理数据的仓库&#xff0c;对数据进行增删改查操作&#xff0c;其本质是一个软件。 首先数据有两种&#xff0c;一种是关系型数据库&#xff0c;另一种是非关系型数据库。 关系型数据库是以表的形式来存储数据&#xff0c;表和表之间可以有很多复杂的关系&a…

nova7(华为)相机关闭画质优化

模板 文章目录 模板 如果对你有帮助&#xff0c;就点赞收藏把&#xff01;(&#xff61;&#xff65;ω&#xff65;&#xff61;)&#xff89;♡ 不知道大家有没有遇到这种苦恼 想拍一张&#xff0c;夜景照片 明明按下快门的时候还是如上图所示 但是到图库就只能看到下图的照片…

多路径 bbr mpbbr 公平性推演

mptcp 推出很久了&#xff0c;先看 rfc6356 三原则&#xff1a; 对自己&#xff0c;mptcp 的吞吐不能比用 sp(single path)tcp 时更差&#xff1b;对它者&#xff0c;mptcp 子流对资源的占用不能侵害其它 sptcp 流量&#xff1b;负载分担&#xff0c;要将孬 subflow 流量分担到…