OAuth 2.0 与 JWT 认证授权详解
【摘要】 OAuth 2.0 与 JWT 认证授权详解本文深入剖析 OAuth 2.0 授权框架与 JWT 令牌机制,帮助你设计安全可靠的认证授权体系。 认证 vs 授权┌─────────────────────────────────────────────────────────┐│ 认证(Authentication):你是谁? —— 验证身份 ││ 授权(Aut...
OAuth 2.0 与 JWT 认证授权详解
本文深入剖析 OAuth 2.0 授权框架与 JWT 令牌机制,帮助你设计安全可靠的认证授权体系。
认证 vs 授权
┌─────────────────────────────────────────────────────────┐
│ 认证(Authentication):你是谁? —— 验证身份 │
│ 授权(Authorization):你能做什么?—— 验证权限 │
│ │
│ OAuth 2.0 = 授权框架(解决"第三方访问资源") │
│ OIDC = 认证层(在 OAuth 之上,解决"身份登录") │
└─────────────────────────────────────────────────────────┘
OAuth 2.0 角色
┌─────────────┐ 1.授权请求 ┌──────────────┐
│ Resource │───────────────→│ Authorization│
│ Owner │←───2.授权许可──│ Server │
│ (用户) │ │ (授权服务器) │
└─────────────┘ └──────────────┘
↑ 3.令牌
┌─────────────┐ │
│ Client │───────────────────────┘
│ (第三方应用) │ 4.携带令牌访问资源
└─────────────┘ ↓
┌──────────────┐
│ Resource │
│ Server │
│ (资源服务器) │
└──────────────┘
| 角色 | 说明 |
|---|---|
| Resource Owner | 资源所有者(用户) |
| Client | 第三方应用 |
| Authorization Server | 授权服务器(颁发令牌) |
| Resource Server | 资源服务器(校验令牌、提供资源) |
四种授权模式
1. 授权码模式(Authorization Code,最推荐)
适用:有后端的 Web 应用(能安全保存 client_secret)
流程:
1. 用户点击登录 → 浏览器跳转授权服务器
GET /authorize?response_type=code&client_id=xxx
&redirect_uri=https://app/callback&scope=read&state=xyz
2. 用户在授权页登录并同意
3. 授权服务器回调:GET https://app/callback?code=ABC&state=xyz
4. 后端用 code 换 token(服务端到服务端,安全)
POST /token { grant_type: authorization_code, code: ABC,
redirect_uri, client_id, client_secret }
5. 返回 access_token / refresh_token
为什么安全:token 不经过浏览器前端暴露,code 一次性
2. 授权码 + PKCE(移动/SPA 场景)
问题:公共客户端无法安全保存 client_secret
PKCE(Proof Key for Code Exchange):
1. 客户端生成 code_verifier(随机串)
2. 计算 code_challenge = SHA256(code_verifier)
3. 授权请求带 code_challenge
4. 换 token 时带 code_verifier
5. 服务器校验 SHA256(code_verifier) == code_challenge
→ 防止授权码被拦截后盗用
3. 客户端凭证模式(Client Credentials)
适用:服务间通信,无用户参与
POST /token
grant_type=client_credentials
&client_id=xxx
&client_secret=yyy
&scope=api.read
→ 直接返回 access_token(代表"应用自己"而非用户)
4. 密码模式(Password,已不推荐)
适用:第一方应用,且无法用其他模式
POST /token
grant_type=password&username=u&password=p
&client_id=xxx
问题:客户端需接触用户密码,安全风险高,OAuth 2.1 已移除
模式选择:
| 场景 | 推荐模式 |
|---|---|
| Web 应用(有后端) | 授权码模式 |
| SPA / 移动 App | 授权码 + PKCE |
| 服务间调用 | 客户端凭证 |
| 第一方可信应用 | 授权码(避免密码模式) |
JWT 令牌详解
结构:三段式
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJzdWIiOiIxIn0 . SflKxwRJ...
Header (Base64Url) Payload (Base64Url) Signature
Header:
{ "alg": "HS256", "typ": "JWT" }
Payload(Claims):
{
"sub": "user_123", // subject 主体
"iss": "https://auth.example.com", // 签发者
"aud": "api.example.com", // 受众
"exp": 1735689600, // 过期时间
"iat": 1735686000, // 签发时间
"nbf": 1735686000, // 生效时间
"jti": "unique-id", // JWT ID,防重放
"scope": "read write", // 权限
"roles": ["admin"] // 角色
}
Signature:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
三种 Claims 类型:
| 类型 | 说明 | 示例 |
|---|---|---|
| Registered | 标准声明 | sub, iss, aud, exp |
| Public | 公共声明 | 自定义但需防冲突 |
| Private | 私有声明 | 业务自定义 |
JWT 的优缺点
✅ 优点:
- 自包含:信息在令牌内,无需查库
- 无状态:适合分布式、水平扩展
- 跨域友好:可放 Authorization 头
❌ 缺点:
- 无法主动撤销(签发后有效期内一直有效)
- 体积较大(比 session id 大)
- 敏感信息不可放(payload 仅 Base64,可解码)
- 需妥善管理密钥与算法
安全风险与防范
风险 1:算法混淆攻击(alg=none / 非对称混淆)
攻击:把 header 的 alg 改成 none,或把 RS256 改成 HS256,
用公钥当 HMAC 密钥伪造签名
防范:
1. 服务端固定校验算法,拒绝客户端指定的 alg
2. 校验时明确指定期望算法,不接受 none
3. 非对称场景公钥绝不用于对称验证
风险 2:令牌泄露
防范:
1. 传输必须 HTTPS
2. access_token 存内存,避免 localStorage(XSS 风险)
3. refresh_token 用 HttpOnly + Secure + SameSite Cookie
4. 短有效期 access_token + refresh_token 轮换
5. 支持 refresh_token 撤销与重用检测
风险 3:签名密钥管理
防范:
1. 密钥强度足够(HS256 密钥 ≥ 256 位随机)
2. 非对称更佳:授权服务器持私钥签名,资源服务器用公钥验证
3. 通过 JWKS(/.well-known/jwks.json)分发公钥,支持密钥轮换
4. 密钥托管在 KMS/Secret Manager,不入代码库
实战:令牌校验流程
// 资源服务器校验 JWT(伪代码)
public Claims validateToken(String token) {
// 1. 解析并验证签名(使用缓存的 JWKS 公钥)
Jws<Claims> jws = Jwts.parserBuilder()
.setSigningKeyResolver(jwksResolver) // 按 kid 选公钥
.requireIssuer("https://auth.example.com")
.requireAudience("api.example.com")
.build()
.parseClaimsJws(token);
// parseClaimsJws 会自动校验:
// - 签名/算法
// - exp(过期)、nbf(生效时间)
// - iss、aud(若 require 配置)
return jws.getBody();
}
// 2. 权限校验(scope / roles)
public void authorize(Claims claims, String requiredScope) {
String scope = claims.get("scope", String.class);
if (scope == null || !scope.contains(requiredScope)) {
throw new AccessDeniedException("insufficient scope");
}
}
# 网关统一校验(如 Spring Cloud Gateway)
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.example.com
jwk-set-uri: https://auth.example.com/.well-known/jwks.json
最佳实践
- 优先授权码 + PKCE:公共客户端不再用隐式/密码模式
- access_token 短有效期(如 15 分钟),refresh_token 长效但可撤销
- 令牌轮换:refresh_token 一次性使用,重放即撤销整条令牌链
- 最小权限 scope:按需授权,避免一次性要全权限
- 强校验:算法固定、iss/aud/exp 全校验、JWKS 密钥轮换
- 不存敏感信息:JWT payload 可解码,别放身份证、手机号
- 集中式吊销:如需即时撤销,可引入令牌内省(introspection)或黑名单
- 审计与监控:记录令牌签发、失败校验、异常重放
总结
| 概念 | 要点 |
|---|---|
| OAuth 2.0 | 授权框架,四种模式,授权码(+PKCE)最推荐 |
| OIDC | 认证层,在 OAuth 上增加 id_token |
| JWT | 自包含无状态令牌,三段 Base64Url + 签名 |
| 安全核心 | 固定算法、HTTPS、短有效期、刷新轮换、JWKS |
| 撤销难题 | JWT 天然难撤销,用短效 + introspection 缓解 |
设计认证授权体系的核心:OAuth 负责"如何安全地拿到令牌",JWT 负责"令牌如何自证身份与权限",安全则取决于算法、密钥、有效期与传输的每一处细节。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)