Files
tiku-backend.net/docs/architecture/security-and-tenancy.md

125 lines
6.8 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.

# 认证、授权与租户隔离
本文说明当前请求实际经过的安全边界。新增接口、实体或后台任务时,必须保持这些边界闭合。
## 认证入口
API 支持两组认证接口:
- `/api/auth/**` 返回 access token 与 refresh token适合 Bearer 客户端。
- `/api/browser-auth/**` 把 token 写入 HttpOnly Cookie适合同源浏览器客户端。
当前登录方式:
- 平台账号:账号/密码。
- 租户账号:手机号/密码、手机号/短信验证码。
- 租户可配置微信网页授权和微信小程序授权。
主要流程包括短信发送、密码登录、短信登录、微信登录、refresh、logout、logout-all 和首次登录强制改密。具体请求与响应字段以 Scalar 为准。
密码至少 8 位,并必须同时包含字母和数字。连续 5 次失败触发 15 分钟 Identity lockout。短信验证码由本服务生成和哈希发送 Provider 只负责投递;验证码校验最多允许 5 次尝试。
## JWT 与 Session
- access token 使用 RSA SHA-256 签名,默认有效期 15 分钟。
- refresh token 默认有效期 30 天,服务端只保存哈希。
- JWT 必须包含用户、Session、`jti`、签发时间和 `realm`;租户 realm 还必须包含租户 ID。
- 每次 JWT 认证都会核对数据库 Session、用户/成员状态、安全版本和租户上下文,不把 JWT 声明当作永久授权事实。
- refresh token 轮换并检测重放logout 撤销当前 Sessionlogout-all 撤销用户全部 Session。
- 平台 token 只能在平台 Host 使用;租户 token 必须与 Host 或允许路径上的 tenant code 解析结果一致。上下文冲突返回 401不允许静默切换租户。
Production 必须显式配置 JWT `KeyId`、私钥和验证公钥集合,不能使用 Development 临时密钥。
## 浏览器 Cookie 与 CSRF
Browser Auth 使用 access、refresh 和 CSRF Cookie
- access/refresh Cookie 为 HttpOnly。
- Bearer handler 只会在同源浏览器请求中回退读取 access Cookie显式 `Authorization` header 优先。
- 使用 Cookie 的非安全方法必须通过 `BrowserCsrfMiddleware` 的 Origin/Referer 与 CSRF token 校验。
- 跨源浏览器使用必须同时正确配置 `Cors``BrowserAuth:AllowedOrigins`;允许凭据时不能使用通配 Origin。
非浏览器客户端应使用 Bearer token不应复制浏览器 Cookie 流程。
## Realm、Permission、Feature 与 DataScope
每个受保护操作可能同时经过四层判断:
```text
Realmplatform / tenant
+ BackendPermission操作权限
+ SaaSFeature套餐能力
+ DataScope资源范围
```
- Realm 防止平台身份、租户员工和学生身份跨授权域复用。
- `BackendPermission` 控制 `view/manage/read/write/operate` 等操作。
- `SaaSFeature` 是固定代码目录当前包括后台基础、私有题库、练习、作业、考试、词汇、手册、视频、分数线、站点内容、学生管理、学生商城、CRM、推广分佣和教师 AI。
- 菜单由有效 Permission 与 Feature 共同推导,只用于 UI bootstrap不是 API 授权依据。
- DataScope 支持 `All``Restricted``Self`。无法提供可靠资源 predicate 时返回空查询,不能退化为“当前租户全部数据”。
- 套餐状态、Feature override 和额度使用量来自 PostgreSQLRedis 只用于失效通知和缓存,不能成为授权真相。
Controller 默认受 Fallback Policy 保护,匿名接口必须显式标记 `[AllowAnonymous]``EndpointAuthorizationMetadataConvention` 为非匿名 Controller endpoint 补充 realm、module、permission、Feature 操作、All-only DataScope 和审计元数据,集成测试从运行时 `EndpointDataSource` 验证覆盖。
## Host 与租户上下文
`TenantResolutionMiddleware` 在认证前解析租户:
1. 对平台 Host不默认建立租户上下文。
2. 对非平台 Host按启用的租户域名查找租户未匹配且不属于豁免路径时返回 404。
3. 只有 `TenantCodePathPrefixes` 明确允许的路径,才能在平台 Host 使用 `x-tenant-code``tenantCode` 解析租户。
4. JWT tenant ID 与已解析租户必须一致,否则认证失败。
Development 默认平台 Host 是 `localhost``127.0.0.1`。Production 启动校验要求:
- 至少一个非 loopback 的正式平台 Host
- 非通配 `AllowedHosts`
- 至少一个合法的 `TrustedProxyAddresses`
- 仅信任一跳且来源位于可信代理列表的 `X-Forwarded-For/Host/Proto`
客户端不得通过任意 header、query 或转发头绕过以上路径和可信代理限制。
## 数据库租户隔离
当前 PostgreSQL 连接角色不依赖 RLS。租户隔离由以下机制共同完成
### 查询
`TikuDbContext` 自动为所有包含 `TenantId` 的实体应用 Query Filter。普通请求只有在租户上下文已解析且 ID 匹配时可见System Scope 才能绕过。
模型启动校验会拒绝:
-`TenantId` 但未实现 `ITenantOwned` 的实体;
- 缺少租户 Query Filter 的实体;
- 未包含 `TenantId` 且未显式声明全局唯一的 unique index
- 租户实体之间未使用租户限定 principal key 的外键。
### 写入
`TenantIsolationSaveChangesInterceptor` 检查新增、修改和删除实体的租户所有权,防止普通请求写入其他租户或伪造 `TenantId`。Controller 与 Service 不应接受可任意填写的租户 ID、owner tenant ID、bucket 或 Secret 引用。
### 数据库约束
能用 FK、unique 和 check 表达的规则优先使用 EF 配置。当前集中 PostgreSQL guard 额外保证:
- `TenantQuestionReference` 只能指向平台公共题或当前租户私题,且 source 必须匹配所有者类型。
- `TaxonomyNode` 的父节点只能属于平台主体或当前租户。
- 已发布 SaaS 套餐版本及其 Feature/额度清单不可修改,并校验订阅与订单快照的一致性。
这些 guard 由 Migration helper 统一安装和移除,不允许在多份 Migration 中复制 SQL。
## System Scope 与可靠事件
跨租户 Worker、迁移、seed 和平台级后台操作必须通过 `ITenantContextInitializer.InitializeSystem` 或受审计的 `ITenantExecutionScope` 进入 System Scope并提供明确原因。业务代码不得直接关闭 Query Filter。
配置 RabbitMQ 时:
- API 使用 EF Bus Outbox把业务写入、审计和消息放在同一数据库事务边界。
- Worker Consumer 使用 EF inbox/outbox 和有限即时重试。
- Session、成员、租户和套餐状态始终从 PostgreSQL 重新校验,不等待消息消费后才失效。
- 延时/定时重试使用 PostgreSQL `RunAfter`,不依赖 RabbitMQ delayed-message 插件。
## 安全配置门禁
Production 还会在启动时验证 Redis、RabbitMQ、Data Protection 证书、租户 Secret master key、短信 pepper、CORS 和外部服务配置。完整配置入口见[配置与后台任务](../operations.md)。