OAuth 核心概念 #
概述 #
OAuth 2.0 定义了一系列核心概念,理解这些概念是掌握 OAuth 的基础。本文将深入讲解每个核心概念的细节。
text
┌─────────────────────────────────────────────────────────────┐
│ OAuth 核心概念 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 令牌 │ │ 端点 │ │ 客户端 │ │
│ │ Tokens │ │ Endpoints │ │ Clients │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 授权范围 │ │ 授权类型 │ │ 授权请求 │ │
│ │ Scopes │ │ Grant Types │ │ Requests │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
令牌(Tokens) #
访问令牌(Access Token) #
访问令牌是 OAuth 中最重要的概念,它是访问受保护资源的凭证。
text
┌─────────────────────────────────────────────────────────────┐
│ 访问令牌 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 定义:用于访问受保护资源的凭证 │
│ │
│ 特点: │
│ - 由授权服务器颁发 │
│ - 有一定的有效期 │
│ - 代表用户授予的权限范围 │
│ - 可以是任意格式 │
│ │
│ 使用方式: │
│ 在 HTTP 请求头中携带 │
│ Authorization: Bearer <access_token> │
│ │
└─────────────────────────────────────────────────────────────┘
令牌响应示例 #
json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1//0g...",
"scope": "profile email"
}
令牌类型 #
| 类型 | 描述 | 使用场景 |
|---|---|---|
| Bearer | 持有者令牌,最常用 | 大多数 OAuth 实现 |
| MAC | 消息认证码令牌 | 需要额外安全验证 |
| PoP | 所有权证明令牌 | 高安全要求场景 |
Bearer 令牌使用 #
http
GET /api/userinfo HTTP/1.1
Host: resource.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
javascript
const response = await fetch('https://api.example.com/userinfo', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
刷新令牌(Refresh Token) #
刷新令牌用于获取新的访问令牌,无需用户重新授权。
text
┌─────────────────────────────────────────────────────────────┐
│ 刷新令牌 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 定义:用于获取新访问令牌的凭证 │
│ │
│ 特点: │
│ - 有效期通常比访问令牌长 │
│ - 可以多次使用(可配置) │
│ - 可以被撤销 │
│ - 不直接用于访问资源 │
│ - 需要安全存储 │
│ │
│ 使用场景: │
│ - 访问令牌过期后获取新令牌 │
│ - 长期访问用户资源 │
│ - 减少用户重复授权 │
│ │
└─────────────────────────────────────────────────────────────┘
刷新令牌流程 #
text
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 客户端 │ │ 授权服务│ │ 资源服务│
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ 访问资源 │ │
│──────────────────────────────>│
│ │ │
│ 令牌过期 │ │
│<──────────────────────────────│
│ │ │
│ 刷新令牌请求 │ │
│──────────────>│ │
│ │ │
│ 新访问令牌 │ │
│<──────────────│ │
│ │ │
│ 再次访问资源 │ │
│──────────────────────────────>│
│ │ │
│ 返回数据 │ │
│<──────────────────────────────│
│ │ │
刷新令牌请求 #
http
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=1//0g...
&client_id=your_client_id
&client_secret=your_client_secret
刷新令牌响应 #
json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1//0h...",
"scope": "profile email"
}
令牌生命周期 #
text
┌─────────────────────────────────────────────────────────────┐
│ 令牌生命周期 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户授权 │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 颁发令牌 │ │
│ │ Access + │ │
│ │ Refresh │ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ 过期 ┌─────────────┐ │
│ │ 使用访问令牌 │ ─────────> │ 刷新令牌 │ │
│ │ 访问资源 │ │ 获取新令牌 │ │
│ └─────────────┘ └──────┬──────┘ │
│ ▲ │ │
│ │ ▼ │
│ │ ┌─────────────┐ │
│ └──────────────────│ 新访问令牌 │ │
│ └─────────────┘ │
│ │
│ 撤销场景: │
│ - 用户主动撤销 │
│ - 令牌泄露 │
│ - 密码修改 │
│ - 安全事件 │
│ │
└─────────────────────────────────────────────────────────────┘
令牌安全存储 #
text
访问令牌存储位置:
┌─────────────────────────────────────────────────────────────┐
│ 存储位置对比 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 浏览器环境: │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ localStorage│ │ sessionStorage│ │ Cookie │ │
│ │ ❌ 不推荐 │ │ ⚠️ 一般 │ │ ✅ 推荐 │ │
│ │ 易受XSS攻击 │ │ 关闭丢失 │ │ HttpOnly │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ 移动端: │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Keychain │ │ Keystore │ │
│ │ (iOS) │ │ (Android) │ │
│ │ ✅ 推荐 │ │ ✅ 推荐 │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ 服务器端: │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 数据库加密 │ │ Redis │ │ 内存 │ │
│ │ ✅ 推荐 │ │ ✅ 推荐 │ │ ⚠️ 一般 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
端点(Endpoints) #
OAuth 2.0 定义了几个标准端点,用于完成授权流程。
授权端点(Authorization Endpoint) #
text
┌─────────────────────────────────────────────────────────────┐
│ 授权端点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用途:用于用户授权,获取授权码 │
│ │
│ 请求方式:GET │
│ │
│ 示例: │
│ https://accounts.google.com/o/oauth2/v2/auth │
│ https://github.com/login/oauth/authorize │
│ │
│ 必需参数: │
│ - response_type:响应类型(code/token) │
│ - client_id:客户端标识 │
│ - redirect_uri:回调地址 │
│ - scope:授权范围 │
│ - state:防CSRF状态值 │
│ │
└─────────────────────────────────────────────────────────────┘
授权请求示例 #
http
GET /authorize?response_type=code
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb
&scope=profile%20email
&state=xyzABC123 HTTP/1.1
Host: auth.example.com
令牌端点(Token Endpoint) #
text
┌─────────────────────────────────────────────────────────────┐
│ 令牌端点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用途:用于获取和刷新令牌 │
│ │
│ 请求方式:POST │
│ │
│ 示例: │
│ https://oauth2.googleapis.com/token │
│ https://github.com/login/oauth/access_token │
│ │
│ 功能: │
│ - 用授权码换取令牌 │
│ - 刷新访问令牌 │
│ - 客户端凭证授权 │
│ - 密码模式授权 │
│ │
└─────────────────────────────────────────────────────────────┘
令牌请求示例 #
http
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb
&client_id=s6BhdRkqt3
&client_secret=gX1fPt3W
刷新令牌端点 #
通常与令牌端点相同,通过 grant_type 区分:
http
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=8xLOxBtZp8
&client_id=s6BhdRkqt3
&client_secret=gX1fPt3W
撤销端点(Revocation Endpoint) #
text
┌─────────────────────────────────────────────────────────────┐
│ 撤销端点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用途:撤销访问令牌或刷新令牌 │
│ │
│ 请求方式:POST │
│ │
│ RFC:RFC 7009 │
│ │
│ 示例: │
│ https://oauth2.googleapis.com/revoke │
│ │
└─────────────────────────────────────────────────────────────┘
撤销请求示例 #
http
POST /revoke HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token
端点发现 #
OAuth 2.0 授权服务器元数据(RFC 8414):
http
GET /.well-known/oauth-authorization-server HTTP/1.1
Host: auth.example.com
响应示例:
json
{
"issuer": "https://auth.example.com",
"authorization_endpoint": "https://auth.example.com/authorize",
"token_endpoint": "https://auth.example.com/token",
"revocation_endpoint": "https://auth.example.com/revoke",
"scopes_supported": ["profile", "email", "openid"],
"response_types_supported": ["code", "token"],
"grant_types_supported": [
"authorization_code",
"implicit",
"refresh_token"
]
}
客户端(Clients) #
客户端类型 #
OAuth 2.0 定义了两种客户端类型:
text
┌─────────────────────────────────────────────────────────────┐
│ 客户端类型 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 机密客户端(Confidential Client) │ │
│ │ │ │
│ │ 特点: │ │
│ │ - 能够安全存储 client_secret │ │
│ │ - 运行在服务器端 │ │
│ │ - 可以使用所有授权类型 │ │
│ │ │ │
│ │ 示例: │ │
│ │ - Web 服务器应用 │ │
│ │ - 后端服务 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 公共客户端(Public Client) │ │
│ │ │ │
│ │ 特点: │ │
│ │ - 无法安全存储 client_secret │ │
│ │ - 运行在用户设备上 │ │
│ │ - 需要使用 PKCE 增强安全 │ │
│ │ │ │
│ │ 示例: │ │
│ │ - 单页应用(SPA) │ │
│ │ - 原生移动应用 │ │
│ │ - 桌面应用 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
客户端注册 #
在使用 OAuth 之前,客户端需要在授权服务器注册:
text
注册时需要提供:
├── 应用名称
├── 应用类型(Web/原生/SPA)
├── 重定向 URI(redirect_uri)
├── 允许的授权类型
├── 允许的授权范围
└── 其他元数据
注册后获得:
├── client_id(客户端标识)
└── client_secret(客户端密钥,仅机密客户端)
注册示例 #
json
{
"client_name": "My Awesome App",
"redirect_uris": [
"https://myapp.example.com/callback",
"https://myapp.example.com/auth/callback"
],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "profile email",
"token_endpoint_auth_method": "client_secret_basic"
}
客户端认证 #
机密客户端需要在令牌端点进行认证:
Basic 认证 #
http
POST /token HTTP/1.1
Host: auth.example.com
Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
POST 参数认证 #
http
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&client_id=s6BhdRkqt3
&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
客户端配置文件 #
OAuth 2.0 定义了几种客户端配置文件:
| 配置文件 | 描述 | 推荐授权类型 |
|---|---|---|
| Web Application | 服务器端 Web 应用 | 授权码模式 |
| User Agent | 单页应用(SPA) | 授权码 + PKCE |
| Native Application | 原生移动/桌面应用 | 授权码 + PKCE |
授权范围(Scopes) #
Scope 的作用 #
text
┌─────────────────────────────────────────────────────────────┐
│ Scope 作用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 权限控制 │
│ - 限制令牌的访问权限 │
│ - 实现最小权限原则 │
│ │
│ 2. 用户知情 │
│ - 用户知道应用请求哪些权限 │
│ - 增强透明度 │
│ │
│ 3. 权限隔离 │
│ - 不同令牌可以有不同权限 │
│ - 降低安全风险 │
│ │
│ 4. 增量授权 │
│ - 可以逐步请求更多权限 │
│ - 减少用户首次授权负担 │
│ │
└─────────────────────────────────────────────────────────────┘
Scope 示例 #
Google OAuth Scopes #
text
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/calendar
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/gmail.send
GitHub OAuth Scopes #
text
repo - 完整仓库访问
user - 用户信息
user:email - 用户邮箱
read:org - 读取组织信息
gist - 创建 Gist
微信 OAuth Scopes #
text
snsapi_base - 静默授权,获取用户基本信息
snsapi_userinfo - 获取用户详细信息
Scope 请求方式 #
http
GET /authorize?response_type=code
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb
&scope=profile%20email%20openid
&state=xyzABC123 HTTP/1.1
Host: auth.example.com
Scope 响应 #
令牌响应中包含授权的范围:
json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "profile email"
}
Scope 最佳实践 #
text
1. 请求最小必要权限
❌ scope=profile email calendar drive gmail
✅ scope=profile email
2. 使用标准 Scope 名称
✅ openid, profile, email
3. 增量授权
首次登录:scope=openid profile
需要时再请求:scope=openid profile calendar
4. 检查返回的 Scope
授权服务器可能授予比请求更少的权限
授权类型(Grant Types) #
四种主要授权类型 #
text
┌─────────────────────────────────────────────────────────────┐
│ 授权类型概览 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. authorization_code(授权码) │
│ 最安全、最完整的授权方式 │
│ 适用于:服务器端应用 │
│ │
│ 2. implicit(简化模式) │
│ 直接返回令牌,无授权码 │
│ 适用于:纯前端应用(已不推荐) │
│ │
│ 3. password(密码模式) │
│ 直接使用用户密码换取令牌 │
│ 适用于:高度信任的第一方应用 │
│ │
│ 4. client_credentials(客户端凭证) │
│ 使用客户端凭证获取令牌 │
│ 适用于:服务间通信,无用户参与 │
│ │
│ 扩展类型: │
│ - refresh_token:刷新令牌 │
│ - urn:ietf:params:oauth:grant-type:jwt-bearer:JWT 断言 │
│ - urn:ietf:params:oauth:grant-type:saml2-bearer:SAML断言 │
│ │
└─────────────────────────────────────────────────────────────┘
授权类型选择 #
| 场景 | 推荐授权类型 | 原因 |
|---|---|---|
| Web 服务器应用 | authorization_code | 安全性最高 |
| 单页应用(SPA) | authorization_code + PKCE | 防止授权码泄露 |
| 原生移动应用 | authorization_code + PKCE | 安全性保障 |
| 服务间通信 | client_credentials | 无需用户参与 |
| 第一方应用 | password(谨慎使用) | 高度信任场景 |
| IoT 设备 | device_code | 无浏览器场景 |
授权请求参数 #
通用参数 #
text
┌─────────────────────────────────────────────────────────────┐
│ 授权请求参数 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 必需参数: │
│ ├── response_type:响应类型 │
│ │ - code:授权码模式 │
│ │ - token:简化模式 │
│ │ │
│ ├── client_id:客户端标识 │
│ │ │
│ └── redirect_uri:回调地址 │
│ - 必须与注册时一致 │
│ - 必须是绝对 URI │
│ │
│ 推荐参数: │
│ ├── scope:授权范围 │
│ │ │
│ └── state:防 CSRF 状态值 │
│ - 必须是不可猜测的随机值 │
│ - 必须验证返回的 state │
│ │
│ 可选参数: │
│ ├── response_mode:响应模式 │
│ │ - query:查询参数(默认) │
│ │ - fragment:URL 片段 │
│ │ - form_post:表单提交 │
│ │ │
│ ├── prompt:提示模式 │
│ │ - none:不显示授权页面 │
│ │ - login:强制重新登录 │
│ │ - consent:强制显示授权页面 │
│ │ - select_account:选择账户 │
│ │ │
│ ├── login_hint:登录提示 │
│ │ │
│ └── acr_values:认证上下文参考值 │
│ │
└─────────────────────────────────────────────────────────────┘
PKCE 参数 #
text
PKCE(Proof Key for Code Exchange)参数:
├── code_challenge:挑战码
│ - 由 code_verifier 生成
│ - 生成方法:code_challenge = BASE64URL(SHA256(code_verifier))
│
└── code_challenge_method:挑战方法
- S256:SHA-256(推荐)
- plain:明文(不推荐)
状态参数(State) #
State 的作用 #
text
┌─────────────────────────────────────────────────────────────┐
│ State 参数作用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 防止 CSRF 攻击 │
│ - 确保响应与请求来自同一会话 │
│ - 防止攻击者伪造授权响应 │
│ │
│ 2. 维护会话状态 │
│ - 可以在 state 中编码应用状态 │
│ - 授权后恢复用户上下文 │
│ │
│ 3. 防止重放攻击 │
│ - 每次请求使用新的 state │
│ - 验证后立即失效 │
│ │
└─────────────────────────────────────────────────────────────┘
State 使用示例 #
javascript
function generateState() {
return crypto.randomBytes(16).toString('hex');
}
const state = generateState();
session.oauthState = state;
const authUrl = `https://auth.example.com/authorize?` +
`response_type=code&` +
`client_id=${clientId}&` +
`redirect_uri=${encodeURIComponent(redirectUri)}&` +
`scope=profile%20email&` +
`state=${state}`;
res.redirect(authUrl);
State 验证 #
javascript
app.get('/callback', (req, res) => {
const { code, state } = req.query;
if (state !== session.oauthState) {
return res.status(400).send('Invalid state parameter');
}
delete session.oauthState;
});
重定向 URI(Redirect URI) #
Redirect URI 要求 #
text
┌─────────────────────────────────────────────────────────────┐
│ Redirect URI 要求 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 必须是绝对 URI │
│ ✅ https://example.com/callback │
│ ❌ /callback │
│ │
│ 2. 必须与注册时一致 │
│ - 协议、主机、端口、路径都必须匹配 │
│ - 查询参数可选匹配 │
│ │
│ 3. 必须使用 HTTPS(生产环境) │
│ ✅ https://example.com/callback │
│ ❌ http://example.com/callback │
│ │
│ 4. 不能是 localhost(生产环境) │
│ - 开发环境可以例外 │
│ │
│ 5. 不能使用通配符 │
│ ❌ https://*.example.com/callback │
│ │
└─────────────────────────────────────────────────────────────┘
Redirect URI 示例 #
text
注册的 Redirect URI:
https://example.com/auth/callback
允许的请求:
✅ https://example.com/auth/callback
✅ https://example.com/auth/callback?foo=bar
不允许的请求:
❌ http://example.com/auth/callback(协议不同)
❌ https://example.com:443/auth/callback(端口显式指定)
❌ https://example.com/callback(路径不同)
❌ https://sub.example.com/auth/callback(子域名不同)
本地开发 Redirect URI #
text
本地开发时可以使用:
http://localhost:3000/callback
http://127.0.0.1:3000/callback
http://[::1]:3000/callback
注意:
- 仅用于开发环境
- 生产环境必须使用 HTTPS
错误响应 #
授权错误 #
text
┌─────────────────────────────────────────────────────────────┐
│ 授权错误响应 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 错误通过 redirect_uri 返回: │
│ │
│ https://client.example.com/cb?error=access_denied │
│ &error_description=The%20user%20denied%20access │
│ &state=xyz │
│ │
│ 标准错误码: │
│ ├── invalid_request:请求参数错误 │
│ ├── unauthorized_client:客户端未授权 │
│ ├── access_denied:用户拒绝授权 │
│ ├── unsupported_response_type:不支持的响应类型 │
│ ├── invalid_scope:无效的授权范围 │
│ ├── server_error:服务器错误 │
│ └── temporarily_unavailable:服务暂时不可用 │
│ │
└─────────────────────────────────────────────────────────────┘
令牌错误 #
json
{
"error": "invalid_grant",
"error_description": "The provided authorization code is invalid or expired.",
"error_uri": "https://auth.example.com/docs/errors/invalid_grant"
}
令牌错误码 #
| 错误码 | 描述 |
|---|---|
| invalid_request | 请求缺少必需参数 |
| invalid_client | 客户端认证失败 |
| invalid_grant | 授权码/刷新令牌无效 |
| unauthorized_client | 客户端未授权使用此授权类型 |
| unsupported_grant_type | 不支持的授权类型 |
| invalid_scope | 请求的范围无效 |
概念关系图 #
text
┌─────────────────────────────────────────────────────────────┐
│ OAuth 核心概念关系 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Client │ │
│ │ (客户端) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Client ID │ │ Client Type │ │ Redirect URI│ │
│ │ │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Grant Type │ │
│ │ (授权类型) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │Authorization│ │ Token │ │ Refresh │ │
│ │ Endpoint │ │ Endpoint │ │ Endpoint │ │
│ └──────┬──────┘ └──────┬──────┘ └─────────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────┐ │
│ │ │ Tokens │ │
│ │ │ (令牌) │ │
│ │ └──────┬──────┘ │
│ │ │ │
│ │ ┌─────────┼─────────┐ │
│ │ │ │ │ │
│ │ ▼ ▼ ▼ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ │Access │ │Refresh │ │ ID │ │
│ │ │ Token │ │ Token │ │ Token │ │
│ │ └────────┘ └────────┘ └────────┘ │
│ │ │ │
│ └───────────────┼────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Scope │ │ State │ │
│ │ (授权范围) │ │ (状态参数) │ │
│ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
下一步 #
现在你已经掌握了 OAuth 的核心概念,接下来学习 授权码模式,了解最安全、最完整的授权流程!
最后更新:2026-03-28