Token相关设计
文章目录
- 1. 双Token 机制概述
- 1.1 访问令牌(Access Token)
- 1.2 刷新令牌(Refresh Token)
- 2. 双Token 认证流程
- 3. Spring Boot 具体实现
- 3.1 生成 Token(使用 JWT)
- 3.2 解析 Token
- 3.3 登录接口(返回双 Token)
- 3.4 刷新 Token 接口
- 3.5 退出登录
- 4. 总结 🚀
在微服务架构中,Token 认证是保障系统安全性的重要手段,常见的方式包括 JWT(JSON Web Token) 及 基于 Redis 的 Token 认证。本文将介绍 双Token 机制 及其具体实现。
1. 双Token 机制概述
1.1 访问令牌(Access Token)
- 用途:前端每次请求携带该令牌,用于身份认证。
- 有效期:较短(如10分钟 - 2小时)。
- 存储方式:前端存储(如 LocalStorage、SessionStorage、HTTP Only Cookie)。
- 信息载荷:用户 ID、权限、过期时间等。
1.2 刷新令牌(Refresh Token)
- 用途:用于获取新的 Access Token,避免用户频繁登录。
- 有效期:较长(如7天 - 30天)。
- 存储方式:数据库或 Redis(不能存储在前端,防止滥用)。
- 信息载荷:用户 ID,仅用于重新获取 Access Token。
2. 双Token 认证流程
-
用户登录
- 用户提交用户名、密码。
- 后端校验通过后,生成 Access Token(短期) 和 Refresh Token(长期)。
- Access Token 通过 JWT 方式返回给前端。
- Refresh Token 存储到数据库或 Redis,避免前端篡改。
-
请求 API 资源
- 前端在每次请求时,携带
Authorization: Bearer <Access Token>
。 - 后端解析 Access Token,校验有效性。
- 通过则返回资源,失败则根据错误码处理(如
401 Unauthorized
)。
- 前端在每次请求时,携带
-
Token 过期时的处理
-
Access Token 过期,但 Refresh Token 仍有效 :
- 前端调用 刷新接口,携带 Refresh Token 请求新 Access Token。
- 后端验证 Refresh Token 后,重新生成 Access Token 并返回。
-
Refresh Token 过期或无效:
- 需要用户重新登录。
-
-
用户登出
- 后端删除 Refresh Token 记录。
- 前端删除 Access Token。
3. Spring Boot 具体实现
3.1 生成 Token(使用 JWT)
import io.jsonwebtoken.*;
import java.util.Date;public class JwtUtil {private static final String SECRET_KEY = "your_secret_key";private static final long ACCESS_TOKEN_EXPIRATION = 2 * 60 * 60 * 1000; // 2小时private static final long REFRESH_TOKEN_EXPIRATION = 7 * 24 * 60 * 60 * 1000; // 7天// 生成 Access Tokenpublic static String generateAccessToken(String userId) {return Jwts.builder().setSubject(userId).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION)).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();}// 生成 Refresh Tokenpublic static String generateRefreshToken(String userId) {return Jwts.builder().setSubject(userId).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + REFRESH_TOKEN_EXPIRATION)).signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();}
}
3.2 解析 Token
public static Claims parseToken(String token) {return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
3.3 登录接口(返回双 Token)
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/login")public Map<String, String> login(@RequestBody LoginRequest request) {// 1. 校验用户名和密码(省略)// 2. 生成 TokenString accessToken = JwtUtil.generateAccessToken(request.getUsername());String refreshToken = JwtUtil.generateRefreshToken(request.getUsername());// 3. 存储 Refresh Token(示例使用 Redis)redisTemplate.opsForValue().set("refresh_token:" + request.getUsername(), refreshToken, 7, TimeUnit.DAYS);// 4. 返回 TokenMap<String, String> tokens = new HashMap<>();tokens.put("accessToken", accessToken);tokens.put("refreshToken", refreshToken);return tokens;}
}
3.4 刷新 Token 接口
@PostMapping("/refresh")
public ResponseEntity<Map<String, String>> refresh(@RequestHeader("Authorization") String refreshToken) {// 1. 校验 Refresh TokenClaims claims = JwtUtil.parseToken(refreshToken);String userId = claims.getSubject();// 2. 检查 Redis 是否存储该 Refresh TokenString storedToken = redisTemplate.opsForValue().get("refresh_token:" + userId);if (storedToken == null || !storedToken.equals(refreshToken)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();}// 3. 生成新的 Access TokenString newAccessToken = JwtUtil.generateAccessToken(userId);// 4. 返回新的 TokenMap<String, String> tokens = new HashMap<>();tokens.put("accessToken", newAccessToken);return ResponseEntity.ok(tokens);
}
3.5 退出登录
@PostMapping("/logout")
public ResponseEntity<Void> logout(@RequestHeader("Authorization") String accessToken) {Claims claims = JwtUtil.parseToken(accessToken);String userId = claims.getSubject();// 删除 Redis 中的 Refresh TokenredisTemplate.delete("refresh_token:" + userId);return ResponseEntity.ok().build();
}
4. 总结 🚀
机制 | 作用 | 过期时间 | 存储位置 |
---|---|---|---|
Access Token | 用于 API 认证 | 短(10分钟-2小时) | 前端 LocalStorage/SessionStorage |
Refresh Token | 用于刷新 Access Token | 长(7天-30天) | Redis/数据库 |
- 双 Token 机制 既保证了安全性(短期有效的 Access Token)又提升了用户体验(长期有效的 Refresh Token)。
- Access Token 过期时,通过 Refresh Token 重新获取,而无需重新登录。
- Refresh Token 需要存储在后端(如 Redis),避免前端泄露。
博客主页: 总是学不会.
相关文章:
Token相关设计
文章目录 1. 双Token 机制概述1.1 访问令牌(Access Token)1.2 刷新令牌(Refresh Token) 2. 双Token 认证流程3. Spring Boot 具体实现3.1 生成 Token(使用 JWT)3.2 解析 Token3.3 登录接口(返回…...
【时序预测】在线学习:算法选择(从线性模型到深度学习解析)
——如何为动态时序预测匹配最佳增量学习策略? 引言:在线学习的核心价值与挑战 在动态时序预测场景中(如实时交通预测、能源消耗监控),数据以流式(Streaming)形式持续生成,且潜在的…...

React antd的datePicker自定义,封装成组件
一、antd的datePicker自定义 需求:用户需要为日期选择器的每个日期单元格添加一个Tooltip,当鼠标悬停时显示日期、可兑换流量余额和本公会可兑流量。这些数据需要从接口获取。我需要结合之前的代码,确保Tooltip正确显示,并且数据…...

学生管理前端
文章目录 首页student.html查询功能 首页 SpringBoot前端html页面放在static文件夹下:/src/main/resources/static 默认首页为index.html,我们可以用两个超链接或者两个button跳转到对应的页面。这里只是单纯的跳转页面,不需要提交表单等其…...

深入理解并实现自定义 unordered_map 和 unordered_set
亲爱的读者朋友们😃,此文开启知识盛宴与思想碰撞🎉。 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 在 C 的标准模板库(STL)中,unorder…...
顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-大模型电话机器人
语音流直接对接Realtime API 多模态大模型 直接把音频流输出给大模型,大模型返回音频流。 顶顶通CTI对Realtime API 的支持 提供了以下2个APP可对接任意 •cti_audio_stream 通过TCP推流和播放流,适合用于人机对话场景。 •cti_unicast_start 通过旁…...

kinova机械臂绿色灯一闪一闪及刷机方法
一、背景 实验室有两个kinova mico机械臂,但经常出现操纵杆上的绿色灯一闪一闪的,导致无法使用操纵杆或ROS进行控制,下面给出官方的教程以及所需要的FS 0CPP 0008_6.2.5_mico_6dof.hex文件。 重要的东西写在前面: a、如果出现操…...
第16天:C++多线程完全指南 - 从基础到现代并发编程
第16天:C多线程完全指南 - 从基础到现代并发编程 一、多线程基础概念 1. 线程创建与管理(C11) #include <iostream> #include <thread>void hello() {std::cout << "Hello from thread " << std::this_…...

中科大计算机网络原理 1.5 Internt结构和ISP
一、互联网的层次化架构 覆盖范围分层 主干网(Tier-1级) 国家级或行业级核心网络,承担跨区域数据传输和全球互联功能。例如中国的四大主干网(ChinaNET、CERNET等)以及跨国运营商(如AT&T、Deuts…...

Windows安装sql server2017
看了下官网的文档,似乎只有ubuntu18.04可以安装,其他debian系的都不行,还有通过docker的方式安装的。 双击进入下载的ISO,点击执行可执行文件,并选择“是” 不要勾选 警告而已,不必理会 至少勾选这两…...
计算机网络之传输层(tcp协议)
一、TCP协议的特点 面向连接:TCP使用面向连接的通信模式,通信双方需要先建立连接,然后才能进行数据的传输。连接建立过程采用三次握手的方式。 可靠性:TCP提供可靠的数据传输服务,确保数据的完整性、有序性和正确性。…...

从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)?
本文首发:从零到一:如何用阿里云百炼和火山引擎搭建专属 AI 助手(DeepSeek)? 阿里云百炼和火山引擎都推出了免费的 DeepSeek 模型体验额度,今天我和大家一起搭建一个本地的专属 AI 助手。 阿里云百炼为 …...

Open3D解决SceneWidget加入布局中消失的问题
Open3D解决SceneWidget加入布局中消失的问题 Open3D解决SceneWidget加入布局中消失的问题1. 问题2. 问题代码3. 解决 Open3D解决SceneWidget加入布局中消失的问题 1. 问题 把SceneWidget加到布局管理其中图形可以展示出来,但是鼠标点击就消失了。 stackoverflow上已…...

计算机毕业设计Python+DeepSeek-R1大模型游戏推荐系统 Steam游戏推荐系统 游戏可视化 游戏数据分析(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...

Linux笔记---缓冲区
1. 什么是缓冲区 在计算机系统中,缓冲区(Buffer) 是一种临时存储数据的区域,主要用于协调不同速度或不同时序的组件之间的数据传输,以提高效率并减少资源冲突。它是系统设计中的重要概念,尤其在I/O操作、网…...
如何流畅访问github
1.传输数据原理 本地计算机通过本地网接入运营骨干网,经过DNS域名解析,将输入的字符解析为要连接的真实IP地址,服务器返还一个数据包(github)给计算机 2.原因 DNS域名污染-DNS解析出现问题,导致访问一个不存在的服务器 3.解决…...

java基础+面向对象
Java基础语法 CMD命令 cls 清屏 cd 目录进入文件 cd… 退回 dir 查看当前目录所有文件 E:进入E盘 exit 退出 环境变量就是不用去专门的盘符去找,直接去环境变量里找到文件 语言优势 编译型语言c: 整体翻译 解释型语言python&#x…...
Linux 检测内存泄漏方法总结
文章目录 strace检测asan内存检测linux下gperf工具(tcmalloc)检查C/C代码内存泄露问题参考 strace检测 (1)启动程序 (2) strace -f -p <PID> -tt -e brk,mmap,mmap2,munmapbrk 变大 → 说明堆增长…...

本地部署deepseek大模型后使用c# winform调用(可离线)
介于最近deepseek的大火,我就在想能不能用winform也玩一玩本地部署,于是经过查阅资料,然后了解到ollama部署deepseek,最后用ollama sharp NUGet包来实现winform调用ollama 部署的deepseek。 本项目使用Vs2022和.net 8.0开发,ollam…...

Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)
一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库,旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础,许多 其他的数据处理库(如Pandas、SciPy)都依赖于Num…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...