title: Authentication description: OpenID Connect 认证(Authentication)是通过 ID Token 将用户身份验证结果安全地传递给客户端的核心机制。
🔐 3. Authentication
OpenID Connect 的主要功能是通过身份认证(Authentication)帮助终端用户登录,或者判断终端用户是否已经登录。
认证的结果以一种安全的方式从服务器返回给客户端(Relying Party, RP),
使客户端能够信赖该认证结果。
认证结果通过 ID Token 返回,其中包含关于认证的信息(如发行者、用户标识符、认证时间等)。
🔄 认证流程类型
OpenID Connect 支持以下三种认证流程:
1. 授权码流程(Authorization Code Flow)
- 使用
response_type=code - 最安全的方式,所有令牌均通过服务器到服务器传输,避免暴露给浏览器。
- 支持 刷新令牌(Refresh Token)。
2. 隐式流程(Implicit Flow)
- 使用
response_type=id_token或response_type=id_token token - 适用于前端应用(如 SPA),令牌直接返回到浏览器。
- 不支持刷新令牌,令牌可能暴露。
3. 混合流程(Hybrid Flow)
- 使用
response_type=code id_token、code token或code id_token token - 结合授权码和隐式流程的优点,适合复杂场景。
⚖️ 流程比较
| 属性 | 授权码流程 | 隐式流程 | 混合流程 |
|---|---|---|---|
| 令牌从授权端点返回 | 否 | 是 | 否 |
| 令牌从令牌端点返回 | 是 | 否 | 否 |
| 令牌是否对用户代理隐藏 | 是 | 否 | 否 |
| 客户端是否能认证 | 是 | 否 | 是 |
| 支持刷新令牌 | 是 | 否 | 是 |
| 仅需单次通信 | 否 | 是 | 否 |
| 主要通过服务器通信 | 是 | 否 | 视情况而定 |
🔁 响应类型与流程关系
response_type | 流程类型 |
|---|---|
code | 授权码流程 |
id_token | 隐式流程 |
id_token token | 隐式流程 |
code id_token | 混合流程 |
code token | 混合流程 |
code id_token token | 混合流程 |
💡 说明:
response_type=code来源于 OAuth 2.0 (RFC 6749),
而包含id_token的响应类型则定义在 OAuth 2.0 多重响应类型扩展 中。
🧩 3.1. 使用授权码流程(Authorization Code Flow)
授权码流程是 OpenID Connect 最安全、最推荐的认证方式,
适用于能安全存储客户端密钥(Client Secret)的服务端应用。
3.1.1. 授权码流程步骤
- 请求授权码:客户端向授权端点发起请求,成功后返回授权码。
- 交换令牌:客户端携带授权码请求 Token Endpoint,返回 ID Token + Access Token。
- 验证 ID Token:客户端验证签名与声明。
- 获取用户标识:从
subClaim 获取唯一用户标识。
优势
- 令牌不暴露给浏览器
- 支持客户端认证
- 可使用刷新令牌
- 适合高安全场景(如金融系统)
3.1.2. 授权端点(Authorization Endpoint)
授权端点用于执行 终端用户认证与授权。
客户端通过重定向用户代理触发认证流程。
请求参数
| 参数 | 是否必需 | 说明 |
|---|---|---|
client_id | ✅ | 客户端标识符 |
response_type | ✅ | 指定授权类型,如 code |
redirect_uri | ✅ | 用户认证成功后的回调地址 |
scope | ✅ | 权限范围,必须包含 openid |
state | ✅ | 防止 CSRF 的随机值 |
nonce | 可选 | 防止重放攻击 |
prompt | 可选 | 控制 UI 行为,例如强制重新登录 |
示例请求
GET /authorize?client_id=s6BhdRkqt3
&response_type=code
&scope=openid%20email
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com安全要求
- 所有通信 必须使用 TLS
- 验证
redirect_uri与注册时一致
3.1.3. 令牌端点(Token Endpoint)
Token Endpoint 用于交换授权码获取令牌。
Token 请求
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb成功响应
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIs..."
}错误响应
{
"error": "invalid_request"
}⚙️ Token 响应必须携带
Cache-Control: no-store。
3.1.4. ID Token 验证规则
客户端验证 ID Token 时需检查:
- 签名是否有效(JWS 验证或 TLS 信任)
iss与发行者一致aud包含client_id- 当前时间 <
exp - 若存在
nonce,需与请求一致 - 若存在
at_hash或c_hash,需匹配访问令牌或授权码哈希
⚡ 3.2. 隐式流程(Implicit Flow)
隐式流程主要用于浏览器端应用。 所有令牌直接从授权端点返回,不使用 Token Endpoint。
示例请求
GET /authorize?
response_type=id_token%20token
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&scope=openid%20profile
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj响应
HTTP/1.1 302 Found
Location: https://client.example.org/cb#
access_token=SlAV32hkKG
&token_type=bearer
&id_token=eyJ0...NiJ9
&expires_in=3600
&state=af0ifjsldkj⚠️ 所有响应参数都附加在重定向 URI 的
#fragment部分。 客户端必须解析 fragment 并验证 ID Token。
🔗 3.3. 混合流程(Hybrid Flow)
混合流程结合了授权码与隐式流的优点。 部分令牌从授权端点返回,部分从 Token 端点返回。
响应示例
HTTP/1.1 302 Found
Location: https://client.example.org/cb#
code=SplxlOBeZQQYbYS6WxSbIA
&id_token=eyJ0...NiJ9
&state=af0ifjsldkj特点
| 参数 | 说明 |
|---|---|
code | 授权码 |
id_token | 身份令牌 |
access_token | 可选访问令牌 |
c_hash | 授权码哈希 |
at_hash | 访问令牌哈希 |
ID Token 附加要求
- 必须包含
nonce - 若返回
access_token,必须包含at_hash - 若返回
code,必须包含c_hash
✅ 小结
| 流程 | 安全性 | 是否返回 ID Token | 是否支持刷新 | 推荐场景 |
|---|---|---|---|---|
| Authorization Code | ⭐⭐⭐⭐ | ✅ | ✅ | 服务器端应用 |
| Implicit | ⭐ | ✅ | ❌ | 前端 SPA |
| Hybrid | ⭐⭐⭐ | ✅ | ✅ | 复杂场景 |
💬 总结
- 授权码流程 是最安全、最常用的方式。
- 隐式流程 适用于无法安全保存密钥的浏览器端。
- 混合流程 适合既需要快速响应又要高安全的场景。
无论使用哪种流程,核心目标都是: ✅ 安全地验证终端用户身份并传递可信的认证结果。
---
### ✅ 建议命名
- 文件路径:`/docs/oidc/authentication.mdx`
- `_meta.ts` 中菜单项:
```ts
export default {
index: 'Overview',
'id-token': 'ID Token',
authentication: 'Authentication',
}