Files
tiku-backend.net/docs/architecture/authentication-authorization-security.md

129 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 认证、授权与 Host 安全策略
本文是当前生效安全规范。新增接口或修改登录流程时以本文档和自动化测试为准前端菜单、JWT 字符串和历史角色约定不能代替 API 授权。
## 授权域
- `tenant`:租户业务域,必须绑定 Active 租户和 Active `TenantMembership`
- `platform`:平台运营域,只能从配置的 Platform Host 进入,不绑定租户。
核心规则:
- Host、JWT scope、tenant claim、数据库 Session 和请求租户上下文必须一致。
- JWT 只证明已认证会话,不承载可直接授权的角色或权限。
- 后台权限每次从数据库角色绑定解析;菜单只控制 UI 展示。
- 数据权限必须进入 SQL无法可靠映射 owner、region 或 class 的资源采用 All-only fail-closed。
- 用户、成员、租户、后台角色、权限、SecurityStamp 或 Session 任一失效,旧 token 不能继续取得能力。
- Controller 默认要求认证;公开接口必须显式 `[AllowAnonymous]`
```text
Client
-> Trusted proxy
-> TenantResolutionMiddleware
-> JWT + AuthSession validation
-> Authorization handler + current access context
-> EF tenant filter + DataScope SQL + PostgreSQL constraints
```
## 账号与 Session
- 账号由 ASP.NET Core Identity 管理。
- 密码最少 10 位PBKDF2 迭代次数 210,000。
- 连续 5 次密码失败后锁定 15 分钟。
- TOTP、恢复码和 Authenticator Key 使用 Identity 标准能力。
- 微信等外部身份只保存 provider subject、openid、unionid不保存 `session_key` 或原始 secret。
- Data Protection key 持久化到 PostgreSQL非 Development 环境必须提供带私钥的 PKCS#12 证书保护 key ring。
Access token
- RSA SHA-256 签名Header 必须包含 `kid`
- 固定 15 分钟。
- 包含 `sub``sid``jti``iat``iss``aud``exp``scope`
- tenant token 必须包含 `tid`platform token 禁止包含 `tid`
- 完成 MFA 的 Session 可包含 `amr=mfa`
- 不包含 role 或 permission claim。
Refresh token
```text
v2.{t|p}.{tenantId|-}.{sessionId}.{64-byte-random-secret}
```
- 数据库只保存完整 refresh token 的 SHA-256 hash。
- 刷新在事务内轮换 Session。
- 并发刷新只允许一个成功。
- 已轮换 token 被复用时视为重放,撤销整个 token family 并写审计。
- logout 撤销当前 refresh token familylogout-all 更新 SecurityStamp 并撤销用户全部 Session。
## Host 与 tenant 解析
Host 是认证上下文,不是普通参数。`TenantResolutionMiddleware` 在 Authentication 前执行。
| 请求入口 | 租户上下文 | 允许 realm | 默认结果 |
| --- | --- | --- | --- |
| Platform Host | 无租户 | platform白名单入口可用 tenantCode 引导 tenant 登录 | 继续 |
| Active 租户 Host | Host 绑定租户 | tenant | 继续 |
| 租户 Host + 其他 tenantCode/header | 冲突 | 无 | 403 |
| Platform Host + platform realm + tenantCode | 非法混合 | 无 | 400 |
| 未知 Host | 无 | 无 | 非豁免路径 404 |
| Pending/禁用域名 | 无 | 无 | 404 |
规则:
- 自定义域名不接受 `tenantCode``host` query 或客户端转发头覆盖。
- tenant JWT 的 `tid` 必须与 Host 解析租户一致。
- platform JWT 不能访问租户 Host。
- 平台 Host 上的租户登录引导才允许受控使用 `tenantCode`
- 只接受可信代理写入的 Forwarded Headers直连客户端伪造无效。
## RBAC、菜单与 DataScope
租户后台与平台后台角色分离:
- 租户角色、权限、菜单、用户角色绑定都带租户上下文。
- 平台角色不带租户键,不能自动读取租户业务数据。
- 菜单只决定 UI bootstrap 展示,不作为 API 授权依据。
- 后台 API 必须声明明确 permission高风险写操作按策略要求 MFA 和审计。
DataScope
- `All`:当前租户内该模块全部资源。
- `Restricted`:按 region/class/owner 等资源关系过滤。
- `Self`:只允许当前用户关联资源。
- 无法可靠表达资源关系的模块只允许 `All`,不能退化为仅按 tenant 查询。
## 短信验证码
- 验证码生成、哈希、频控、过期和校验由自有业务服务负责。
- `ISmsProvider` 只负责发送。
- 发送失败必须记录失败状态,不能留下可验证验证码。
- 登录、绑定、找回密码等场景使用独立 purpose 和频控键。
## 审计与错误
必须落审计:
- 登录、刷新重放、logout-all、强制改密、MFA 变更;
- 角色、权限、成员状态、租户状态、Provider 配置、支付运营动作;
- System Scope 和跨租户平台操作。
错误响应:
- 401未认证或 token/session 无效。
- 403已认证但 realm、tenant、permission、DataScope、MFA 或套餐能力不满足。
- 404未知 Host、不可见资源或需要隐藏存在性的资源。
- 响应不得泄露完整手机号、openId、邮箱、密钥、支付账号或内部 provider payload。
## 生产配置清单
- 正式 `PlatformHosts`
- 可信代理地址和网络 ACL。
- 非通配 `AllowedHosts`
- JWT issuer、audience、当前 `KeyId`、RSA 私钥和旧公钥集合。
- Data Protection 证书。
- CORS 明确 Origin。
- Secret encryption key。
- 短信、对象存储、支付、通知和 AI provider 只通过租户 Provider 配置读取密钥。
待补强事项见 [认证与授权待补强清单](authentication-authorization-hardening-plan.md)。