Skip to content

OAuth 2.0 与 OpenID Connect ​

OAuth 解决客户端获得资源访问授权的问题;OpenID Connect(OIDC)在其上定义用户认证结果。把“拿到了某个平台的 Access Token”直接当作本站用户身份,会遗漏令牌受众、主体来源和账号关联等边界。

OIDC 定义的身份层和 ID Token 见 OpenID Connect Core。仅提供 OAuth 的平台,需要使用该平台明确规定的用户信息接口与主体标识规则,不能自行伪造一套 ID Token 解释。

四个角色 ​

角色在第三方登录中的对应
资源所有者授予访问权限的用户
客户端希望接入登录或 API 的业务应用
授权服务器验证用户、处理授权并签发令牌的一方
资源服务器接受 Access Token 的 API,如 UserInfo

OIDC 中提供认证的一方称为 OP,依赖认证结果的应用称为 RP。一个服务可以同时承担多种角色,但它们的验证职责仍应分开。

授权码流程 ​

以有服务端的 Web 应用为例,浏览器传递授权码,应用后端向提供方兑换令牌。登录事务保存预期提供方、state、nonce、PKCE verifier、回跳目标与过期时间,并绑定发起浏览器。

授权请求使用精确注册的 redirect_uri 与 PKCE challenge。图中自调用表示必须成功的本地处理,任一关联、令牌或账号校验失败都停止登录,不创建正式会话;state、nonce 与 PKCE 的分工见下一节。

客户端只在后端保存上游令牌时,浏览器最终持有本地 Session Cookie 即可,没必要把上游 Refresh Token 再交给页面脚本。

state、nonce 与 PKCE ​

机制关联对象验证位置
state本次登录发起与回调、浏览器上下文回调入口
nonce本次 OIDC 请求与 ID TokenID Token 校验
PKCE授权请求与授权码兑换方Token Endpoint

应用统一使用授权码与 PKCE S256,同时保留一次性 state 和 OIDC nonce,是便于审计的设计选择。标准对不同条件允许使用的防护组合有更细规定,见 RFC 9700 §2.1;不能把 PKCE 解释成无条件替代所有请求关联检查。

PKCE 的 S256 计算为:

text
code_challenge = BASE64URL(SHA256(ASCII(code_verifier)))

verifier 使用密码学安全随机数,每次授权事务独立生成,长度与编码按 RFC 7636;不把固定字符串、用户 ID 或普通 UUID 拼接当作替代。服务端保存原值用于兑换,授权请求只带 challenge。

ID Token 验证 ​

采用成熟 OIDC 库,按 Core §3.1.3.7与提供方元数据进行验证。应用至少需要明确以下配置与检查:

  • 信任的 issuer、签名算法与该 issuer 的密钥来源。
  • aud 是否包含本客户端,多个受众时按规范处理 azp。
  • 时间声明是否有效,nonce 是否匹配此次请求。
  • 要求近期认证或特定强度时,检查约定的 auth_time、acr 等结果。
  • 如再读取 UserInfo,其 sub 必须与 ID Token 对应主体一致。

不能根据客户端请求参数随意信任一个新 issuer,也不能根据未验证令牌中的地址去发现密钥。多身份提供方要绑定发起时的配置,并防范 issuer 混淆;发现元数据与重定向地址同样需要受信配置。

回调是一次性业务事务 ​

登录事务只保存随机 state,却不绑定发起浏览器,也可能接受攻击者从另一个浏览器搬来的回调。可通过安全关联 Cookie 或服务端预登录会话绑定,并设置短有效期与一次性消费。

并发标签页不能共享唯一一条“当前 state”记录。使用以事务 ID 为键的记录集合,在控制数量的前提下允许多个独立登录流程。

授权码重复兑换通常应失败,应用回调也要防止重复创建账号或重复绑定。可将事务标记为处理中并原子消费;外部兑换超时出现未知结果时,选择安全失败并重新登录,不无限重放回调。

回跳地址保存在服务端或使用严格允许列表。return_to 不能直接允许任意绝对 URL,也要处理 //evil.example、编码绕过和协议差异,避免本站成为开放重定向器。

外部账号映射 ​

首次登录先按 (issuer, sub) 查找绑定。未绑定时,可以进入注册流程或让用户先登录现有账号再显式绑定;不要仅凭邮箱相同自动接管已有账号。

账号被冻结、企业成员被移除或外部身份被解绑后,应用必须拒绝建立对应登录态。外部认证成功只证明提供方的认证判断,本地业务状态仍由本站控制。详细流程见账号模型与生命周期。

客户端差异与旧模式 ​

原生应用优先通过系统浏览器完成授权,回调与安全存储遵循平台要求;SPA 不携带可保密的固定 secret。后台能保密的 Web 客户端也应使用 PKCE,客户端认证与 PKCE 保护的是不同边界。

新设计不采用隐式流程返回 Access Token,也不收集用户在提供方的密码来执行密码授权模式。RFC 9700 对隐式授权给出限制,对资源所有者密码凭据授权规定不得使用;旧系统迁移需要核对兼容性,不能只替换参数名称。

参考资料 ​