Skip to content

使用 OIDC 授权码与 PKCE 代替账号密码登录 #62

Description

@shellRaining

背景

当前网站沿用 CC98 官方前端的 OAuth 2.0 Password Grant。用户在本站登录页输入 CC98 用户名和密码,浏览器再向登录中心的 /connect/token 换取访问令牌。这个流程可以正常使用,但第三方域名上的登录表单会增加用户的信任成本,页面脚本也有机会接触密码。

CC98 登录中心已经提供标准 OIDC discovery,并在创建应用页面中推荐 Authorization Code + PKCE。普通应用无法启用 Resource Owner Password Grant,因此本站应注册自己的应用,让用户在 openid.cc98.org 完成密码、Passkey 或 MFA 验证,本站只处理授权回调和令牌。

实施范围

  • 为生产域名和固定本地开发域名注册独立的 CC98 OIDC 应用,只在前端配置公开的 Client ID。
  • 使用 Authorization Code Flow 和 PKCE S256,不在浏览器代码、环境变量或仓库中保存 Client Secret。
  • 将登录页改为跳转 CC98 登录中心,并新增 /auth/callback 回调路由。
  • 发起授权时生成并保存 statenoncecode_verifier,回调时校验 state,再用授权码和 code_verifier 换取令牌。
  • 请求 openid cc98-api offline_access,继续使用 Access Token 访问现有 API,并用 Refresh Token 续期。
  • 保留登录前页面地址,授权完成后返回原页面;覆盖用户拒绝授权、回调参数缺失、状态不匹配、换取令牌失败和令牌过期等情况。
  • 迁移或清理旧 Password Grant 登录态,避免两套存储格式并存。
  • 更新帮助中心的登录说明,解释跳转登录、授权范围、令牌和撤销授权。

当前项目继续采用浏览器直连 CC98 OpenID 和 API 的纯 SPA 架构。本 issue 不引入 BFF。部署在校外的服务端可能无法访问 CC98 服务,而且这会增加 Session、Cookie、CSRF 和后端运维成本。

建议的应用设置

  • 授权类型:Authorization Code
  • 要求 PKCE:开启
  • 允许明文 PKCE:关闭
  • 要求客户端密钥:关闭
  • 允许通过浏览器重定向返回 Access Token:关闭
  • Scopes:openidcc98-apioffline_access
  • Redirect URI:https://cc98.shellraining.xyz/auth/callback
  • CORS Origin:https://cc98.shellraining.xyz

本地开发使用固定的 http://cc98.localhost:1355 来源和对应回调地址。动态 Vercel Preview 域名不加入授权回调名单。

验收标准

  • 用户在 CC98 登录中心完成登录和授权,本站页面不再出现 CC98 密码输入框。
  • 密码登录、Passkey 和登录中心以后增加的认证方式不需要本站单独适配。
  • 回调只能使用匹配的 state 和 PKCE verifier,授权码不能重复使用。
  • 登录后 /me 和需要账号的论坛 API 正常工作,Access Token 到期后可以续期。
  • 登录前页面恢复、拒绝授权、授权失败、过期和退出登录均有明确反馈。
  • Client Secret、授权码、令牌、Cookie 和真实账号信息不进入仓库或日志。
  • 相关单元测试、构建和浏览器登录验证通过。
  • 帮助中心同步更新登录与授权说明。

参考

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions