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…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
