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…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...