1. OIDC协议基础
OpenID Connect (OIDC) 是构建在 OAuth 2.0 之上的身份认证层。OAuth 2.0 解决的是“授权”问题——允许第三方应用访问受保护资源;OIDC 则解决“认证”问题——让第三方应用验证用户身份并获取用户的基本信息。在生产环境中,OIDC 是单点登录 (SSO)、API 网关认证、微服务间身份传递的基石。
1.1 核心概念与角色
OIDC 协议定义了四个核心角色,理解它们之间的交互是诊断令牌刷新与缓存失效问题的前提:
| 角色 | 英文名称 | 职责说明 |
|---|---|---|
| 终端用户 | End-User | 需要被认证的自然人,持有浏览器或原生客户端 |
| 依赖方 | Relying Party (RP) | 需要验证用户身份的 Web 应用或移动 App,即你的业务系统 |
| OpenID 提供者 | OpenID Provider (OP) | 负责认证用户并颁发令牌的授权服务器,如 Keycloak、Okta、Auth0 |
| 用户信息端点 | UserInfo Endpoint | OP 提供的受保护 API,RP 使用 Access Token 获取用户声明 |
故障排查要点: 在缓存失效场景中,RP 与 OP 之间的时钟偏差、令牌签名密钥轮换、以及 UserInfo 端点的响应延迟,是导致认证失败最常见的三个根因。
1.2 ID Token 与 Access Token 的区别
这是 OIDC 中最容易混淆的一组概念。两者在格式、用途、生命周期和验证方式上存在本质差异:
| 对比维度 | ID Token | Access Token |
|---|---|---|
| 格式 | JWT (JSON Web Token),必须包含标准声明 | JWT 或 opaque(不透明字符串),由 OP 决定 |
| 用途 | 证明用户身份,供 RP 本地验证 | 授权访问受保护资源(如 UserInfo、业务 API) |
| 接收方 | RP(客户端应用) | 资源服务器(Resource Server) |
| 验证方式 | RP 使用 OP 的公钥本地验证签名和声明 | 资源服务器调用 OP 的 introspection 端点或本地验证 JWT |
| 生命周期 | 通常较短(几分钟到几小时),不可刷新 | 可长可短,支持通过 Refresh Token 轮换 |
| 包含信息 | iss、sub、aud、exp、iat、nonce 等认证声明 | scope、client_id、授权范围、可能包含用户标识 |
常见陷阱: 很多开发者在缓存 Access Token 时,错误地将 ID Token 也一并缓存并用于后续请求的用户身份识别。ID Token 过期后不应再被信任,必须通过 Refresh Token 流程重新获取。
1.3 授权码流程(Authorization Code Flow)
授权码流程是 OIDC 中最安全、最常用的流程,适用于有后端服务器的 Web 应用。该流程通过一个临时的授权码(Authorization Code)来交换令牌,确保 Access Token 和 ID Token 不会暴露在浏览器端。
缓存策略建议: 在授权码流程中,RP 应缓存从 UserInfo 端点获取的用户声明,而不是缓存 ID Token。声明缓存时间建议设置为 Access Token 有效期的 80%,避免令牌过期后仍使用陈旧数据。
1.4 隐式流程(Implicit Flow)
隐式流程是 OIDC 的早期流程,专为纯前端应用(如浏览器中的 JavaScript SPA)设计。该流程直接返回 Access Token 和 ID Token,跳过了授权码交换步骤。由于令牌直接暴露在 URL 片段中,安全性较低,OAuth 2.0 Security BCP (RFC 9700) 已不推荐使用,建议使用授权码流程 + PKCE 替代。
1.5 流程对比与选型建议
| 对比维度 | 授权码流程 | 隐式流程 |
|---|---|---|
| 适用场景 | Web 应用(有后端)、移动 App、Native 应用 | 纯浏览器 SPA(已不推荐) |
| 令牌暴露 | 令牌在服务端交换,不暴露给浏览器 | 令牌直接暴露在浏览器 URL 片段中 |
| 安全性 | 高,支持 client_secret 和 PKCE | 低,无法安全存储 client_secret |
| Refresh Token | 支持,可获取 Refresh Token | 不支持,无法刷新令牌 |
| 当前推荐度 | 强烈推荐 | 已弃用,建议迁移 |