小应开发者平台 Logo小应开发者平台

账号快捷登录

更新于 2026-05-25

接口定义与开发适配流程

通过小应账号快捷登录(标准 OIDC Authorization Code + PKCE)完成登录、回调、换 token 和账号绑定。

本文说明开放应用·网站如何通过标准 OIDC Authorization Code + PKCE 接入小应账号快捷登录。

如果你更熟悉 OAuth,可以这样理解:OAuth 2.0 负责安全地把用户带到小应授权页、再把一次性 code 换成 token;OIDC 在这个流程上增加了 id_token,让第三方服务端可以验证用户身份并完成登录。本文涉及的 OIDC 登录流程,本质上就是“OAuth 2.0 Authorization Code + PKCE + 可验签的用户身份凭据”。

相关文档:

接入要求

  • 第三方网站必须使用已登记的 redirect_uri 接收登录结果。
  • client_secret 必须保存在服务端密钥系统或环境变量中。
  • 回调接口必须校验 state
  • token 换取请求必须携带原始 code_verifier
  • 服务端必须验证 id_token 签名与关键 claims。
  • 本地账号绑定必须使用 iss + sub

第三方只需要按标准 OpenID Connect(OIDC)流程把用户重定向到小应 authorization_endpoint。用户完成登录与授权后,小应会跳回第三方登记的 redirect_uri

小应账号快捷登录的 access_token 只用于 /userinfo 端点。第三方不要把它当作其他接口访问凭据,也不要把它当作自己的登录 session。

登录服务端点(OIDC)

优先从 discovery 文档读取端点:

GET https://api.xiaoying.life/oidc/.well-known/openid-configuration

从 discovery 中至少读取并使用以下字段:

Discovery 字段用途
issuer验证 id_token.iss
authorization_endpoint发起授权
token_endpoint用 code 换 token
jwks_uri获取验签公钥
userinfo_endpoint可选,读取用户展示资料

生产默认端点如下:

端点方法用途
https://api.xiaoying.life/oidc/authGET发起授权
https://api.xiaoying.life/oidc/tokenPOST用 code 换 token
https://api.xiaoying.life/oidc/jwksGET获取验签公钥
https://api.xiaoying.life/oidc/userinfoGET/POST读取用户展示资料

协议参数:

能力取值
response_typecode
grant_typeauthorization_code
scopeopenid profile
code_challenge_methodS256
token_endpoint_auth_methodclient_secret_basic
id_token 签名算法EdDSA,通过 discovery / JWT header / JWKS kid 选择公钥

小应账号快捷登录面向单次快速授权和账号绑定。token 响应不包含 refresh_token,也不支持 offline_access scope。第三方完成 id_token 验证后,应使用自己的本地 session 维持用户登录。

登录流程

1. 生成登录请求

第三方服务端生成并保存以下临时状态:

字段要求
state高熵随机值,防 CSRF,回调时必须校验
nonce高熵随机值,防 id_token 重放,验签后必须校验
code_verifierPKCE 原始随机值,服务端临时保存
code_challengeBASE64URL(SHA256(code_verifier))

生成规则:

  • statenonce 至少 128 bit 熵。
  • code_verifier 使用 43-128 个 PKCE 合法字符,推荐 32 字节随机数的 base64url 无填充表示。
  • code_challenge 使用 SHA-256 后的 base64url 无填充表示。
  • 登录 attempt 应保存在服务端 session、Redis、数据库或加密 HttpOnly Cookie 中,TTL 建议 5-10 分钟。

把用户重定向到小应授权端点:

GET https://api.xiaoying.life/oidc/auth
  ?response_type=code
  &client_id=xyc_...
  &redirect_uri=https%3A%2F%2Fthird.example%2Fauth%2Fxiaoying%2Fcallback
  &scope=openid%20profile
  &state=<random_state>
  &nonce=<random_nonce>
  &code_challenge=<pkce_challenge>
  &code_challenge_method=S256

WebView 中可以通过普通页面跳转发起授权:

window.location.href = authorizationUrl

2. 处理回调

小应会跳转回第三方注册的 redirect_uri

成功示例:

GET https://third.example/auth/xiaoying/callback?code=...&state=...

错误示例:

GET https://third.example/auth/xiaoying/callback?error=access_denied&error_description=...&state=...

回调处理要求:

  1. 必须校验 state 与发起登录时保存的值一致。
  2. 如果有 error,结束本次登录尝试并展示失败或重新登录入口。
  3. 如果有 code,用服务端保存的 code_verifier 换 token。
  4. code 只能使用一次。
  5. 无论成功、失败还是取消,当前登录 attempt 都应删除或标记为已消费。

3. 换 token

请求:

POST /oidc/token HTTP/1.1
Host: api.xiaoying.life
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
 
grant_type=authorization_code&
code=<authorization_code>&
redirect_uri=https%3A%2F%2Fthird.example%2Fauth%2Fxiaoying%2Fcallback&
code_verifier=<original_code_verifier>

响应示例:

{
  "access_token": "opaque-or-jwt-access-token",
  "expires_in": 3600,
  "id_token": "eyJ...",
  "scope": "openid profile",
  "token_type": "Bearer"
}

实现要求:

  • Authorization 使用 HTTP Basic,值为 Basic + base64(client_id + ":" + client_secret)
  • 请求体必须是 application/x-www-form-urlencoded,不是 JSON。
  • redirect_uri 必须与发起授权请求和小应登记值完全一致。
  • code_verifier 必须是发起授权时保存的原始值,不是 code_challenge
  • token endpoint 错误响应也使用 OAuth 标准错误字段,接入方不要从错误响应中创建登录态。

4. 验证 id_token

第三方服务端必须验证 id_token

检查项要求
签名使用 jwks_uri 对应公钥验证
iss必须等于 https://api.xiaoying.life/oidc
aud必须等于自己的 client_id
exp未过期
iat合理时间窗口内
nonce必须等于发起登录时保存的 nonce
sub存在且非空
alg / kid使用 JWT header 中的 kidjwks_uri 匹配 key;不要把开发环境公钥写死到代码里

关键 claims:

Claim说明
iss小应 issuer
aud第三方 client_id
sub小应对该第三方主体稳定分配的用户标识
exp / iat标准时间字段
nonce授权请求携带时必须回显

注意:

  • id_token 是登录凭据,验签通过前不要信任其中任何字段。
  • access_token 不是登录凭据;本地登录态应基于已验证的 id_token
  • nicknamepicture 是展示资料,不是身份主键。
  • JWKS 可以按 Cache-Controlkid 缓存;遇到未知 kid 时重新拉取 discovery/JWKS。

5. 建立第三方本地登录态

第三方本地账号绑定规则:

  • 唯一键使用 iss + sub
  • 同一小应开发者主体下多个 client 对同一小应用户会得到相同 sub
  • 不同小应开发者主体对同一小应用户会得到不同 sub
  • 保存完整 iss + sub,避免多身份源场景下冲突。

参考本地表字段:

字段说明
provider固定 xiaoying
issuerhttps://api.xiaoying.life/oidc
subjectid_token 的 sub
localUserId第三方自己的用户 ID
createdAt / updatedAt绑定时间

用户信息

openid profile 下返回以下用户信息:

{
  "sub": "xysub_...",
  "nickname": "小应用户",
  "picture": "https://..."
}

使用规则:

  • sub 是唯一身份标识。
  • nicknamepicture 用于展示,可以变化,可以为空。

第三方可以从 /userinfo 获取可展示资料。若调用 /userinfo,使用 token 响应中的 access_token

GET /oidc/userinfo HTTP/1.1
Host: api.xiaoying.life
Authorization: Bearer <access_token>

处理要求:

  • /userinfo 返回的 sub 必须与已验证 id_token.sub 一致。
  • /userinfo 失败不应影响已经验签成功的登录主流程;可以只创建账号,稍后再补展示资料。
  • 不要长期保存小应账号快捷登录的 access_token,除非你的系统确实需要在短时间内重新拉取 /userinfo

安全检查清单

第三方上线前必须确认:

  • client_secret 只存在服务端密钥系统或环境变量中。
  • 回调接口校验 state
  • token 换取请求携带原始 code_verifier
  • id_token 已验签。
  • 已校验 issaudexpnonce
  • 已校验 /userinfo.sub === id_token.sub,如果调用了 /userinfo
  • 本地账号绑定使用 iss + sub
  • 登录 attempt 有 TTL,成功或失败后会删除。
  • redirect_uri 与小应官方登记值完全一致。
  • access_token 只用于 /oidc/userinfo
  • 没有把小应 access_token 当作第三方自己的登录 session。
  • 没有把 nicknamepicture 当作用户唯一标识。

常见错误

错误或现象原因修复
invalid_clientclient_id / client_secret 错误,或 Basic Auth 格式错误检查小应官方交付的客户端配置和 Authorization: Basic
invalid_grantcode 已过期、已使用、redirect_uri 不一致或 code_verifier 错误重新发起登录,检查 PKCE 和 redirect URI
invalid_request缺少必需参数检查 authorization request
access_denied用户取消授权不创建登录态,允许用户重新登录
invalid_scopescope 超出允许范围使用 openid profile
redirect_uri mismatch回调地址与登记值不完全一致使用小应官方登记的精确 URI
unsupported_response_type使用了非 code flow只使用 Authorization Code
invalid_request + PKCE 相关描述缺少 code_challengecode_challenge_method 不正确使用 S256,并保存原始 code_verifier
jwks_no_matching_key / kid 不匹配本地 JWKS 缓存过旧或验签库未重新拉取清理 JWKS 缓存并重新读取 discovery / JWKS
discovery issuer 与本地配置不一致第三方本地配置的 issuer 不是 discovery 返回的 issuer以小应官方交付的 issuer 为准;生产应为 https://api.xiaoying.life/oidc
state 无效或找不到登录 attempt登录 attempt 丢失、过期,或回调不是当前登录请求发起的不创建登录态,重新发起登录;检查 session/cookie/Redis 是否能跨回调保持状态
nonce 不一致id_token 不属于当前登录 attempt,或本地保存的 nonce 丢失不创建登录态,重新发起登录;检查 attempt 存储
token endpoint 返回 server_error服务端暂时无法完成 token 签发或客户端配置异常不创建登录态;记录请求时间、client_idredirect_uri 和错误响应,联系小应官方技术支持

测试用例

第三方接入完成后至少测试:

  1. 首次使用小应登录,能创建或绑定第三方本地账号。
  2. 再次登录同一小应账号,命中同一个第三方本地账号。
  3. 回调 state 被篡改时登录失败。
  4. nonce 不一致时登录失败。
  5. code_verifier 错误时 token 换取失败。
  6. 用户取消授权时不创建第三方登录态。
  7. client_secret 不出现在浏览器 bundle、日志、URL、前端配置中。
  8. iss + sub 唯一约束生效。
  9. /userinfo.subid_token.sub 不一致时登录失败。
  10. 重复使用同一个 authorization code 时第二次 token 换取失败。
  11. client secret 错误时 token 换取失败,且不会创建本地登录态。
  12. JWKS 缓存刷新后仍能验证新 kid 签发的 id_token
  13. 在小应 App WebView 内打开第三方页面,可以完整完成登录。
  14. 在小应 App WebView 外打开第三方页面时,页面能给出合适提示或隐藏小应登录入口。

接入完成标准

第三方交付前应能证明:

  1. 可以从 discovery 获取端点和 jwks_uri
  2. 可以发起 response_type=codescope=openid profilecode_challenge_method=S256 的授权请求。
  3. 在小应 App WebView 内完成授权后,回调 state 校验通过。
  4. 服务端使用 client_secret_basic 和原始 code_verifier 成功换取 token。
  5. 服务端使用 jwks_uri 验证 id_token 签名,并校验 issaudexpnoncesub
  6. 本地账号表以 issuer + subject 建唯一约束。
  7. 可选调用 /userinfo 时,会校验返回的 sub
  8. 浏览器、前端 bundle、日志和错误上报中都没有 client_secret、authorization code、id_token 或小应账号快捷登录 access_token 明文泄漏。