2. 授权码模式详解:授权码请求、用户授权、授权码发放、令牌交换、访问令牌与刷新令牌的获取流程
授权码模式(Authorization Code Grant)是 OAuth 2.0 中最完整、最安全的授权流程,适用于有服务端后端的 Web 应用。其核心在于通过一个临时的“授权码”作为中间凭证,避免访问令牌直接暴露在用户代理(浏览器)中。本节将拆解该模式的五个核心阶段,并配合流程图与关键参数表格进行深度解析。
2.1 授权码模式完整流程概览
整个流程涉及四个角色:资源所有者(用户)、用户代理(浏览器)、客户端(第三方应用)、授权服务器。以下 SVG 图展示了从授权请求发起至令牌获取的完整闭环。
2.2 阶段一:授权码请求(Authorization Request)
客户端引导资源所有者访问授权服务器的 /authorize 端点。此请求通过浏览器重定向完成,关键参数如下:
| 参数 | 是否必需 | 说明 |
|---|---|---|
response_type |
是 | 固定值 code,表示使用授权码模式 |
client_id |
是 | 客户端在授权服务器注册时获得的唯一标识 |
redirect_uri |
是 | 授权码发送回客户端的地址,必须与注册时一致 |
scope |
否 | 请求的权限范围,如 openid profile email |
state |
强烈推荐 | 防 CSRF 攻击的随机字符串,回调时原样返回 |
安全要点:
state 参数是防止跨站请求伪造(CSRF)的关键。客户端必须生成并验证该参数,确保回调请求来自同一用户会话。
2.3 阶段二:用户认证与授权(User Authentication & Consent)
授权服务器收到请求后,执行以下步骤:
- 验证客户端身份:检查
client_id是否有效,redirect_uri是否匹配白名单。 - 用户认证:如果用户未登录,展示登录页面,要求输入凭证(用户名/密码、MFA 等)。
- 展示授权页面:向用户展示客户端请求的权限范围(如“读取您的个人信息”),用户点击“允许”或“拒绝”。
- 记录用户决策:授权服务器记录用户授权结果,生成临时授权码。
最佳实践: 授权页面应清晰列出所有请求的 scope,并提供“记住此授权”选项,减少重复授权操作。
2.4 阶段三:授权码发放(Authorization Code Issuance)
用户授权后,授权服务器生成一个短生命周期的授权码,并通过重定向将授权码发送回客户端指定的 redirect_uri。回调 URL 格式如下:
https://client.example.com/callback?code=AUTHORIZATION_CODE&state=XYZ123
授权码具有以下关键属性:
- 一次性使用:使用后立即失效,防止重放攻击。
- 短生命周期:通常有效期为 1~10 分钟,降低泄露风险。
- 绑定客户端:授权码与特定
client_id和redirect_uri绑定。
安全警告: 授权码必须通过 TLS 传输。如果授权码在传输过程中被截获,攻击者可能利用它换取令牌。务必使用 HTTPS 并验证
state 参数。
2.5 阶段四:令牌交换(Token Exchange)
客户端使用授权码向授权服务器的 /token 端点发起 POST 请求,换取访问令牌和刷新令牌。此步骤在客户端服务端进行,不经过浏览器,安全性更高。
令牌交换请求参数:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://client.example.com/callback
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
| 参数 | 是否必需 | 说明 |
|---|---|---|
grant_type |
是 | 固定值 authorization_code |
code |
是 | 上一步获取的授权码 |
redirect_uri |
是 | 必须与授权请求中的 redirect_uri 一致 |
client_id |
是 | 客户端标识 |
client_secret |
是 | 客户端密钥,用于验证客户端身份 |
2.6 阶段五:访问令牌与刷新令牌获取(Access & Refresh Token)
授权服务器验证授权码和客户端凭证后,返回令牌响应。典型响应如下:
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"scope": "openid profile email"
}
令牌字段说明:
| 字段 | 说明 |
|---|---|
access_token |
访问令牌,用于访问受保护资源,通常为 JWT 格式 |
token_type |
令牌类型,固定为 Bearer |
expires_in |
访问令牌有效期(秒),通常为 3600(1 小时) |
refresh_token |
刷新令牌,用于在访问令牌过期后获取新的访问令牌 |
scope |
实际授予的权限范围,可能与请求的 scope 不同 |
2.7 刷新令牌流程(Refresh Token Flow)
当访问令牌过期时,客户端可以使用刷新令牌获取新的访问令牌,无需用户重新授权。刷新请求如下:
POST /token HTTP/1.1
Host: authorization-server.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
刷新令牌的注意事项:
- 长期有效:刷新令牌有效期通常较长(数天至数月),但可被撤销。
- 轮换策略:每次使用刷新令牌后,授权服务器可返回新的刷新令牌,旧令牌失效。
- 安全存储:刷新令牌必须安全存储在服务端,避免泄露。
关键对比: 访问令牌用于访问资源,生命周期短;刷新令牌用于获取新的访问令牌,生命周期长。两者必须分开存储,刷新令牌不应暴露给前端。
2.8 授权码模式安全断言总结
授权码模式通过以下机制保障安全:
- 授权码隔离:访问令牌不经过浏览器,降低令牌泄露风险。
- 一次性授权码:防止重放攻击。
- 客户端认证:令牌交换阶段要求
client_secret,确保只有合法客户端能换取令牌。 - state 参数:防御 CSRF 攻击。
- 刷新令牌轮换:减少长期令牌泄露的影响。