# 认证与授权待补强清单

> 2026-07-29 实施状态：可信代理启动校验、外部登录成员生命周期、Redis 跨实例频控与故障关闭、固定目录数据库 Capability、事务化 System Scope 审计、MassTransit EF Bus/Consumer Outbox 与即时 BackgroundJob Consumer、浏览器 Cookie/CSRF 主链路及 endpoint manifest 已落地。本地 RabbitMQ 4.3.4 已验证停机期间事务提交、outbox 积压及重启补发；生产网关 ACL 和生产 Broker 演练仍属于部署验收项。

当前生效规则见 [认证、授权与 Host 安全策略](authentication-authorization-security.md)。本文只记录尚需补强的安全事项，不重复描述已实现体系。

## P0：可信代理与 Host fail-closed

- Production 必须配置正式 `PlatformHosts` 和 `TrustedProxyAddresses`。
- Production 不允许只保留 `localhost` / `127.0.0.1` 作为平台 Host。
- 未受信来源伪造 `X-Forwarded-Host` 不能改变 realm 或 tenant context。
- 受信代理只接受一跳转发，网关必须覆盖客户端伪造的 Forwarded Headers。
- API 公网入口必须只能由受信网关访问。

实现说明：应用已强制 `ForwardLimit=1`，Production 缺少正式 Host、显式 `AllowedHosts` 或可信代理地址时启动失败；公网 ACL 和网关覆盖转发头由部署层落实。

验收：

- Host A + Tenant B token 返回 403。
- 未知 Host 的非豁免路径返回 404。
- Production 缺少可信代理或正式平台 Host 时启动失败。

## P0：Disabled / Invited 成员生命周期

- 外部身份登录不得静默恢复 Disabled membership。
- Invited membership 不得被微信登录静默激活。
- 首次外部登录是否允许创建学生成员，必须由租户自注册策略控制。
- 成员恢复只能由管理员显式操作并写审计。

实现说明：`TenantAuthPolicy.AllowExternalStudentSelfRegistration` 控制首次外部登录；Disabled/Invited 不会被登录激活，管理员成员变更会同步撤销 Session、写审计并发布生命周期事件。

验收：

- Disabled 成员旧 access/refresh 立即失效。
- Disabled 成员不能通过微信 Web 或小程序登录恢复。
- 关闭自注册时，首次外部登录被拒绝。

## P1：SaaS Capability 授权

RBAC 只回答“用户是否有操作权限”；Capability 负责“租户是否购买、启用并可使用该能力”。

默认组合：

```text
Tenant Active
  + Subscription 有效
  + Module / Feature 可用
  + Operation Permission
  + DataScope / Resource Scope
```

实现说明：固定 `ProductModuleCatalog`、`PlanModuleEntitlement`、可审计 `TenantModuleOverride` 与 `ICapabilityAccessEvaluator` 已进入数据库授权 Handler；未知或缺失目录模块 fail-closed。平台接口可替换套餐模块权益和设置带原因的租户覆盖，变更在同一事务写审计与 outbox 事件。迁移仅为从未配置权益的存量套餐补齐固定目录，已有显式权益不会被扩权。

验收：

- 有 permission 但套餐不含模块，返回 403。
- 套餐包含模块但没有 permission，返回 403。
- PastDue / Cancelled / Expired 不能创建新的受限资源。
- 修改套餐后，旧 access token 不需要等待过期即可失去能力。

## P1：接口最小权限与 DataScope 审计

- 建立 endpoint authorization manifest：method、route、realm、module、permission、DataScope、audit action。
- 后台写接口不得只使用 `[Authorize]`。
- tenant/platform 权限不得串用。
- `[AllowAnonymous]` 只能出现在白名单路由。
- All-only 资源必须显式声明。
- 新增 Controller action 未进入 manifest 时测试失败。

实现说明：`AuthorizationManifestTests` 对全部 Controller HTTP Action 的 method、route、匿名标记和 policy 生成稳定摘要；MVC convention 同时为全部非匿名 Controller endpoint 生成 realm、module、permission、operation、All-only 与 audit action 运行时元数据，变更会触发测试失败并要求安全评审。

验收：

- 列表、详情、创建、更新、删除、批量、导出和 Worker job 使用一致 DataScope。
- 租户 A 管理员不能读取或操作租户 B 数据。

## P1：System Scope 审计

- `ITenantExecutionScope` 创建 System Scope 时必须记录 caller、reason、target tenant 和 request/job id。
- 平台操作、Worker、迁移验证和受审计公共题库服务才允许使用 System Scope。
- 跨租户写操作必须落 `AuditLog`。

实现说明：`SystemScopeRequest` 强制 caller、reason、target tenant 和 correlation ID；没有租户目标时必须显式声明 `IsGlobal`，且 Worker/公共题库不能创建全局 scope。旧参数签名已移除。成功路径的 entered 审计、跨租户业务写入和 completed 审计处于同一 PostgreSQL 事务，异常路径回滚业务并持久化 entered/failed 审计。

验收：

- 未声明 reason 的 System Scope 创建失败。
- Worker scope 不串租户。
- 高风险平台操作都有审计记录。

## P2：客户端与协议规范

- 浏览器 token 存储策略在正式前固定：纯 Bearer、本域 BFF 或 cookie 方案只能选一种主链路。
- Access token 继续短期有效，不把角色和权限写入 JWT。
- 登录审计和错误响应避免泄露手机号、openId、邮箱完整值。
- 出现第三方生态登录、开放 API 或多客户端授权需求时，再评估 OpenIddict / OIDC，不继续扩展私有协议。

实现说明：浏览器使用 `/api/browser-auth` + Secure/HttpOnly Cookie + Origin/CSRF 校验；原 `/api/auth` Bearer 契约继续供小程序、原生和服务调用。
