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

145 lines
7.1 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 展示。
- 租户后台能力同时要求 Active tenant、有效订阅、模块权益和 operation permissionCapability 仍以 PostgreSQL 为准。
- 数据权限必须进入 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 管理。
- 密码最少 8 位且必须同时包含字母和数字PBKDF2 迭代次数 210,000。
- 连续 5 次密码失败后锁定 15 分钟。
- 普通租户用户使用手机号和密码或手机号短信验证码登录;平台管理员当前使用账号和密码登录。
- 微信等外部身份只保存 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`
- 不包含 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。
浏览器入口使用 `/api/browser-auth/*`access/refresh token 仅写入 Secure、HttpOnly Cookie响应体不返回 token不安全方法必须通过同源 Origin 与双提交 CSRF 校验。`/api/auth/*` Bearer 契约继续供小程序、原生客户端和服务调用。
## 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高风险写操作必须记录审计。
- UI bootstrap 只返回“有效 permission 推导菜单”与有效 Capability 的交集;租户不能绑定当前无权使用的模块权限。
- Trial/Active 且在有效期内可写PastDue/Cancelled/Expired 仅允许已有权益模块的历史读取。
DataScope
- `All`:当前租户内该模块全部资源。
- `Restricted`:按 region/class/owner 等资源关系过滤。
- `Self`:只允许当前用户关联资源。
- 无法可靠表达资源关系的模块只允许 `All`,不能退化为仅按 tenant 查询。
## 短信验证码
- 验证码生成、哈希、频控、过期和校验由自有业务服务负责。
- `ISmsProvider` 只负责发送。
- 发送失败必须记录失败状态,不能留下可验证验证码。
- 登录、绑定、找回密码等场景使用独立 purpose 和频控键。
- Redis Lua 同时执行跨实例 IP、账号、租户、手机号和 purpose 窗口计数key 只使用 GUID 或不可逆哈希。
- Redis 不可用时密码尝试、短信发送和短信校验失败关闭;普通授权请求仍直接查询 PostgreSQL。
## 可靠安全事件
- `Tiku.Contracts` 只包含版本化 DTO不引用 EF、HTTP 或 Provider SDK。
- API 使用 MassTransit EF Bus OutboxWorker consumer 使用 EF inbox/outbox业务变更、审计和消息由同一 DbContext 提交。
- RabbitMQ 消息只负责非权威失效版本、菜单刷新和下游通知成员、租户、Session 或套餐失效不等待 consumer。
- System Scope 只能通过完整 `SystemScopeRequest` 创建;成功路径将 entered 审计、跨租户业务写入和 completed 审计放入同一 PostgreSQL 事务。
## 审计与错误
必须落审计:
- 登录、刷新重放、logout-all、强制改密
- 角色、权限、成员状态、租户状态、Provider 配置、支付运营动作;
- System Scope 和跨租户平台操作。
错误响应:
- 401未认证或 token/session 无效。
- 403已认证但 realm、tenant、permission、DataScope 或套餐能力不满足。
- 404未知 Host、不可见资源或需要隐藏存在性的资源。
- 响应不得泄露完整手机号、openId、邮箱、密钥、支付账号或内部 provider payload。
## 生产配置清单
- 正式 `PlatformHosts`
- 可信代理地址和网络 ACL。
- 非通配 `AllowedHosts`
- JWT issuer、audience、当前 `KeyId`、RSA 私钥和旧公钥集合。
- Data Protection 证书。
- CORS 明确 Origin。
- Redis 7.2+ 连接串Production 缺失时拒绝启动。
- RabbitMQ 4.x Host、virtual host 与凭据Production 缺失时拒绝启动。
- 公网只暴露覆盖 Forwarded Headers 的可信网关API ACL 只允许该网关访问。
- Secret encryption key。
- 短信、对象存储、支付、通知和 AI provider 只通过租户 Provider 配置读取密钥。
待补强事项见 [认证与授权待补强清单](authentication-authorization-hardening-plan.md)。