认证与授权¶
生态系统的所有平台都采用同一套认证模型。本页说明该模型,并为新接入的依赖方 (RP)提供实用指引。
模型概览¶
sequenceDiagram
participant U as 用户
participant RP as RP 应用
participant SSO as Gerege SSO
participant EID as eID Mongolia
participant P as 手机
U->>RP: 点击「登录」
RP->>SSO: Authorization request (code + PKCE)
SSO->>EID: 发起 eID 登录
EID->>P: 二维码 / deep-link / 推送
P-->>EID: PIN1 确认
EID-->>SSO: 公民身份已确认
SSO-->>RP: Authorization code
RP->>SSO: code + code_verifier → 令牌
SSO-->>RP: access + refresh + id_token
RP->>SSO: /userinfo
SSO-->>RP: 用户信息
核心原则:RP 从不直接访问 eID,一切都经由 SSO。
登录方式¶
| 方式 | 类型 | 说明 |
|---|---|---|
| eID | 主要 | 二维码 · 移动端 deep-link · 按登记号推送 |
| 辅助 | 首次绑定必须经 eID 核验 |
不存在的东西:密码、邮箱/OTP 登录、短信 OTP 登录。
这是有意为之的决定。没有密码,就不会泄露密码、不会被撞库复用、也不会被钓鱼。
平台在哪里完成登录 —— AUTH_MODE¶
生态中的平台可以承担两种角色之一:
- 身份服务 —— 平台自行完成用户认证。登录卡片(eID 二维码/登记号 ·
Google)直接出现在它自己的首页和
/login上。 - 依赖方(RP) —— 平台把登录委托给上游 SSO。点击「登录」会跳转到 SSO,用户在那里完成认证后再返回。
这两者不是代码差异,而是配置。由后端的 AUTH_MODE 决定:
| 取值 | 登录界面 |
|---|---|
provider |
登录卡片显示在本平台上 |
client |
跳转到上游 SSO(SSO_ISSUER) |
未设置时,会根据是否配置了 SSO_CLIENT_ID 自动推导。
前端从公开接口 GET /api/v1/site/auth 读取自身模式 —— 无需认证,响应中不含
任何机密:
是否作为 issuer 是另一个问题
AUTH_MODE 回答的是「本平台的用户在哪里登录」。平台本身是否为
其他应用签发令牌,由 OAUTH_ISSUER 单独决定。两者可以同时启用 ——
形成链式结构:平台既为他人签发令牌,又把自己的用户送往上游 IdP。
实际效果:SSO 服务与使用它的平台运行同一份代码。同一个 Docker 镜像会根据 环境变量启动为其中任一角色。详见共享代码。
PIN1 与 PIN2¶
| PIN1 | PIN2 | |
|---|---|---|
| 证书 | Authentication | Signing |
| 用途 | 登录 | 签名 |
| 法律后果 | 无 | 有——不可否认性 |
登录 ≠ 签名
以 PIN1 登录并不意味着用户同意了任何事情。对于具有法律后果的行为 (合同、授权、财务义务),必须另行以 PIN2 签名。
OIDC 技术参数¶
| 项目 | 取值 |
|---|---|
| 流程 | Authorization code + PKCE (S256) |
| Access token | 不透明(opaque) |
id_token |
JWT,RS256 |
| Refresh token | 轮换式,带重用检测 |
| 机器对机器 | client_credentials |
| Discovery | /.well-known/openid-configuration |
| UserInfo | /userinfo |
refresh token 轮换¶
每次使用 refresh token 都会签发新的令牌,旧的随即失效。如果旧令牌被 再次使用,说明可能已遭窃取,因此整条链都会被作废。
所以 RP 在刷新之后必须立即保存新令牌。若继续保留旧的,下一次刷新就会让所有 会话全部掉线。
会话与登出¶
- 会话由 JWT access + refresh 一对令牌承载。
- 登出会同时作废 refresh 与 access(access 拒绝名单)。
- 登出后用户会回到其发起时所在的域名。
成为 RP 的步骤¶
1. 注册应用¶
在 Gerege SSO 控制台创建 client,可得到:
client_id、client_secret。
注册前需要准备:
- redirect URI(所有环境——dev / staging / prod)
- post-logout redirect URI
- 需要申请的 scope
- 应用名称与图标(会显示在用户的授权同意页上)
2. 读取 discovery¶
不要硬编码 endpoint,一律从这里读取。
3. Authorization request¶
实现 authorization code + PKCE (S256) 流程,并务必使用 state 与 nonce。
4. 换取令牌¶
code + code_verifier → access_token、refresh_token、id_token。
5. 校验 id_token¶
必须逐项检查:
- [ ] RS256 签名——使用从 JWKS 获取的密钥
- [ ]
iss与 discovery 中的 issuer 一致 - [ ]
aud等于您的client_id - [ ]
exp尚未过期 - [ ]
nonce与您发送的一致
6. 用户信息¶
从 /userinfo endpoint 获取。
常见错误¶
redirect URI 必须完全一致
要逐字符吻合:结尾的 /、http 与 https 之别、端口、子路径都很重要。
这是最常见的集成错误。
变更域名时的检查清单
变更域名或品牌时,须同时更新以下三处。漏掉任何一处,登录都会 悄无声息地失败:
- [ ] SSO 中的 redirect URI 清单
- [ ] TLS 证书 SAN
- [ ] RP 配置中的 issuer / endpoint 地址
不得跳过 PKCE
即便是机密客户端也要使用 PKCE。额外开销很小,防护效果却是实实在在的。
授权模型¶
认证完成之后就进入权限校验。生态系统的标准层级:
详见通用约定页面。
在机构层面:成员关系由 Postgres RLS 保护——用户只能看到自己所属机构的 数据。这是数据库层面的限制,而不是应用代码里的判断。
授予 manager 权限需要本人以 PIN2 确认——详见
通用约定。