微服务中使用JWT 认证体系详解:HMAC vs RSA 签名、OAuth2 Token 获取机制
微服务中使用JWT 认证体系详解HMAC vs RSA 签名、OAuth2 Token 获取机制一、JWT 基础概念1.1 什么是 JWTJWTJSON Web Token是一种紧凑的、自包含的令牌格式用于在各方之间安全传递信息。它由三部分组成用点号.分隔xxxxx.yyyyy.zzzzz ↓ ↓ ↓ Header Payload SignatureHeader声明令牌类型和签名算法Payload存放实际数据用户ID、权限、过期时间等Signature对前两部分的签名防止数据被篡改1.2 一个 JWT 长什么样eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ0ZXN0IiwiZXhwIjoxNzg0Njc4NDA1fQ.签名部分对 Header 进行 Base64 解码{alg:RS256,// 签名算法typ:JWT// 令牌类型}对 Payload 进行 Base64 解码{user_name:test,member_id:100000,exp:1784678405,// 过期时间Unix 时间戳client_id:my_app,scope:[read,write]}注意Header 和 Payload 只是 Base64 编码不是加密任何人都能解码看到内容。Signature 才是保证数据不被篡改的关键。注博客https://blog.csdn.net/badao_liumang_qizhi二、两种签名算法对比HMAC vs RSA2.1 HMAC对称加密签名代表算法HS256、HS384、HS512原理用一个共享密钥Secret Key对数据进行签名和验签签名方和验签方使用同一个密钥。签名过程HMAC-SHA256(Header . Payload, 密钥) → Signature 验签过程用同一个密钥重新计算签名对比是否一致特点签名和验证都用同一把钥匙速度快、实现简单适合单体系统或前端-后端之间的简单场景密钥泄露 既能伪造又能验证典型场景前端登录后后端用一个 Secret 签发 Token前端携带该 Token 访问同一后端。┌──────────┐ 同一把密钥 ┌──────────┐ │ 登录服务 │ ←────────────────────→ │ 业务服务 │ │ (签发方) │ 签发 验证都用它 │ (验证方) │ └──────────┘ └──────────┘2.2 RSA非对称加密签名代表算法RS256、RS384、RS512原理使用一对公钥-私钥。私钥签名公钥验签。签名方和验签方使用不同的密钥。签名过程RSA-SHA256(Header . Payload, 私钥) → Signature 验签过程用公钥验证签名是否与数据匹配特点私钥签名只有认证服务有公钥验签所有业务服务都可以有公钥泄露无所谓只能验证不能伪造适合分布式微服务架构计算稍慢典型场景独立的认证服务用私钥签发 Token各个微服务用公钥验证 Token 的合法性。┌──────────────┐ │ 认证服务 │ 持有私钥负责签发 Token │ (Auth Server)│ └──────┬───────┘ │ 签发的 Token ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ 服务 A │ │ 服务 B │ │ 服务 C │ │ 持有公钥 │ │ 持有公钥 │ │ 持有公钥 │ │ 只能验证 │ │ 只能验证 │ │ 只能验证 │ └──────────┘ └──────────┘ └──────────┘2.3 核心区别一览维度HMAC (HS256)RSA (RS256)密钥一个共享密钥一对公私钥签发持有密钥的任何人只有持有私钥的一方验证持有密钥的任何人持有公钥的任何人安全性密钥泄露 全部完蛋公钥公开也安全性能快稍慢适用场景单体/简单前后端微服务/多系统密钥管理所有需验证的服务都要密钥只有认证服务有私钥三、为什么微服务架构用 RSA 而不是 HMAC假设你有 20 个微服务都需要验证 Token如果用 HMAC每个服务都要存储同一个密钥任何一个服务泄露密钥攻击者就能伪造 Token密钥轮换时要同时更新 20 个服务如果用 RSA只有认证服务有私钥其他 20 个服务只有公钥泄露了也只能验证不能伪造私钥轮换只改认证服务一处这就是为什么项目使用独立的认证服务 RSA 公钥的架构。四、OAuth2 协议基础4.1 OAuth2 是什么OAuth2 是一套授权框架定义了客户端如何获取访问令牌Access Token。它不关心 Token 的具体格式但通常与 JWT 配合使用。4.2 四种授权模式模式适用场景简述Authorization CodeWeb应用、第三方登录最安全需要浏览器跳转Password Grant内部系统、受信任客户端直接传账号密码换 TokenClient Credentials服务间调用无用户参与纯机器对机器Implicit已废弃不推荐使用4.3 Password Grant 详解客户端(ApiPost/curl) 认证服务(Auth Server) │ │ │ POST /oauth/token │ │ Authorization: Basic base64(id:pw)│ │ Body: grant_typepassword │ │ usernamexxx │ │ passwordxxx │ │──────────────────────────────────→ │ │ │ 验证账号密码 │ │ 用私钥签发 JWT │ { │ │ access_token: eyJ..., │ │ token_type: bearer, │ │ expires_in: 53640, │ │ refresh_token: eyJ... │ │ } │ │←────────────────────────────────── │ │ │请求中的两层认证Basic AuthAuthorization: Basic xxx证明你是哪个客户端应用将client_id:client_password进行 Base64 编码例如demo_app:123456→ZGVtb19hcHA6MTIzNDU2表示我是 demo_app 这个应用Body 中的账号密码证明你代表哪个用户usernamepassword表示我代表 zhangsan 这个用户请求授权4.4 返回结果字段说明{access_token:eyJhbGciOiJSUzI1NiIs...,// 访问令牌调接口时用token_type:bearer,// 令牌类型固定为 bearerrefresh_token:eyJhbGciOiJSUzI1NiIs...,// 刷新令牌用于续期expires_in:53640,// access_token 有效期秒scope:read write,// 授权范围user_name:zhangsan,// 用户名member_id:100000// 业务字段}五、两种 Token 的本质区别以实际场景说明为什么前端登录拿到的 Token不能用于调用微服务接口5.1 前端 Web TokenHMAC 签名浏览器 → 前端登录接口(/open/login) → 返回 coc_jwt放在 Set-Cookie 中签名算法HS512HMAC签发方前端网关/BFF 层验证方同一个前端网关用途标识浏览器会话前端页面鉴权特征密钥只在网关内部微服务拿不到这个密钥5.2 微服务 TokenRSA 签名客户端 → 认证服务(/oauth/token) → 返回 access_tokenJWTRS256 签名签名算法RS256RSA签发方专用认证服务用私钥签名验证方所有微服务用公钥验签用途服务间调用鉴权特征每个微服务配置公钥即可独立验证5.3 为什么不能混用前端 Token (HS512) → 微服务 (配置的是 RSA 公钥) ↓ 尝试用 RSA 公钥验证 HMAC 签名 ↓ ❌ Cannot convert access token to JSON微服务只认识 RSA 签名的 Token。你拿 HMAC 签名的 Token 给它它用 RSA 公钥去验签格式完全对不上所以报错。六、完整认证架构图┌─────────────────────────────┐ │ 认证服务 (Auth Server) │ │ 持有 RSA 私钥 │ │ /oauth/token │ │ 签发 RS256 JWT │ └──────────┬──────────────────┘ │ ┌────────────────┼────────────────┐ │ │ │ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ A 服务 │ │ B 服务 │ │ C 服务 │ │ 端口 3012 │ │ 端口 3013 │ │ 端口 3014 │ │ 配置 RSA 公钥│ │ 配置 RSA 公钥│ │ 配置 RSA 公钥│ │ 独立验签 │ │ 独立验签 │ │ 独立验签 │ └──────────────┘ └──────────────┘ └──────────────┘ ┌─────────────────────────────────────────────────┐ │ 前端网关 (BFF / Gateway) │ │ /open/login → 签发 coc_jwt (HS512) │ │ 用于浏览器 Cookie 会话管理 │ │ 与微服务 Token 体系完全独立 │ └─────────────────────────────────────────────────┘七、通用代码示例7.1 Java Spring Boot 配置 RSA 公钥验签# application.ymlsecurity:jwt:signing-key:|-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... -----END PUBLIC KEY-----resource-ids:my-servicematchers:-path:/api/public/**attribute:permitAll-path:/api/**attribute:authenticated7.2 curl 获取 OAuth2 Token# 将 client_id:client_password 进行 Base64 编码后放入 Basic Authcurl-s-XPOSThttps://auth-server.com/oauth/token\-HContent-Type: application/x-www-form-urlencoded\-umy_client_id:my_client_password\-dgrant_typepasswordusernameuserpasswordpass-u参数等价于-HAuthorization: Basic$(echo-nmy_client_id:my_client_password|base64)7.3 PowerShell 获取 Token# 构造 Basic Auth$pairmy_client_id:my_client_password$base64[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($pair))# 请求 Token$headers {AuthorizationBasic$base64Content-Typeapplication/x-www-form-urlencoded}$bodygrant_typepasswordusernameuserpasswordpass$responseInvoke-WebRequest-Urihttps://auth-server.com/oauth/token-Method POST-Headers$headers-Body$body-UseBasicParsing$token($response.Content|ConvertFrom-Json).access_token7.4 Java 代码获取 TokenRestTemplate/** * 通过 OAuth2 Password Grant 获取访问令牌 */publicStringgetAccessToken(){StringclientIdmy_client_id;StringclientPasswordmy_client_password;StringcredentialsBase64.getEncoder().encodeToString((clientId:clientPassword).getBytes());HttpHeadersheadersnewHttpHeaders();headers.set(Authorization,Basic credentials);headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);MultiValueMapString,StringbodynewLinkedMultiValueMap();body.add(grant_type,password);body.add(username,user);body.add(password,pass);HttpEntityMultiValueMapString,StringrequestnewHttpEntity(body,headers);ResponseEntityMapresponserestTemplate.postForEntity(https://auth-server.com/oauth/token,request,Map.class);return(String)response.getBody().get(access_token);}7.5 使用 Token 调用业务接口# 获取到 token 后curl-s-XPOSThttp://127.0.0.1:8080/api/your-endpoint\-HAuthorization: Bearer eyJhbGciOiJSUzI1NiIs...\-HContent-Type: application/json\-d{pageNum:1,pageSize:10}八、验签过程详解当业务服务收到请求时1. 从 Header 中提取: Authorization: Bearer eyJxxx.eyJyyy.zzz 2. 拆分 JWT 三段: - Header: eyJxxx → 解码得 {alg:RS256,typ:JWT} - Payload: eyJyyy → 解码得 {user_name:test,exp:1784678405,...} - Signature: zzz 3. 用配置的 RSA 公钥验证签名: RSA_Verify(公钥, eyJxxx.eyJyyy, zzz) → true/false 4. 如果签名验证通过: - 检查 exp 是否过期 - 检查 resource-ids 是否匹配 - 提取用户信息注入到 SecurityContext 5. 如果验证失败: - 返回 401 Unauthorized - 错误信息如 Cannot convert access token to JSON格式不对 - 或 Access token expired过期九、总结概念一句话解释JWT一种自包含的令牌格式三段式结构HMAC (HS256/512)对称签名一把钥匙既签又验RSA (RS256)非对称签名私钥签、公钥验OAuth2一套获取令牌的标准流程/协议Password GrantOAuth2 的一种模式直接用账号密码换 TokenBasic Auth用 Base64(id:password) 标识客户端身份Bearer TokenToken 的传递方式放在 Authorization Header 中公钥公开的只能验证签名不能伪造私钥保密的用来签名只有认证服务持有核心理解在微服务架构中认证服务是唯一持有私钥的发证机关各个业务服务通过公钥验证证件的真伪而不需要每个服务都能发证。前端页面用的是另一套简单的会话机制HMAC Cookie两者是独立的认证体系。

相关新闻

MCP为什么正在成为Agent的“USB接口”?开发者先搞懂这4点

MCP为什么正在成为Agent的“USB接口”?开发者先搞懂这4点

摘要: MCP是一套让AI Agent连接外部数据和工具的统一标准。本文从统一连接、能力发现、上下文复用和安全边界4个方面,讲清它为什么被称为Agent的“USB接口”。以前开发AI Agent,如果要接入文件、数据库、GitHub或企业系统,通常要分…

2026/10/25 6:32:29 阅读更多 →
DolphinX 实测:当 AI Agent 真正读懂你的时序数据,事情开始变得不一样

DolphinX 实测:当 AI Agent 真正读懂你的时序数据,事情开始变得不一样

DolphinX 实测:当 AI Agent 真正读懂你的时序数据,事情开始变得不一样 "DolphinDB 有了自己的 AI Agent 平台?"这是我看完 DolphinX 资料后的第一反应。坦白说,在 2026 年这个时间点,“数据库 AI” 已经算不…

2026/10/23 22:28:15 阅读更多 →
北京市专精特新中小企业认定常见问题解答

北京市专精特新中小企业认定常见问题解答

一、已获得科技和创新型中小企业称号,截至上年末从事特定细分市场时间达3年以上,如何理解?答:申请企业需为有效期内的创新型中小企业或科技型中小企业,两者满足其一。细分市场判断的时间是截至上年末(即202…

2026/10/23 16:11:06 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/24 11:09:31 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/24 17:47:00 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/24 18:34:36 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/24 9:46:55 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/25 3:12:30 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/24 21:09:59 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 9:15:56 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 11:09:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 5:28:28 阅读更多 →