# 架构决策：全局 CORS 单一策略

> 日期：2026-08-02  
> 决策：仅使用全局 `CorsFilter`；所有 Controller 禁止 `@CrossOrigin`  
> 本体：`rule:BR-CONFIG-002`、`rule:BR-CONFIG-003`

## 背景

后端已经通过 `CORS_ALLOWED_ORIGINS` 和全局 `CorsFilter` 配置显式 Web Origin，但 17 个 Controller 同时保留了无参数 `@CrossOrigin`。在当前 Filter 顺序下，非白名单请求会先被拒绝；局部注解仍是危险的第二套策略：如果 Filter 注册、请求映射或 Spring 配置方式变化，默认允许全部 Origin 的局部策略可能重新暴露接口。

## 决策

1. 删除全部 Controller 级 `@CrossOrigin`，不允许页面或接口自行扩展 Origin。
2. 生产 profile 继续要求 `CORS_ALLOWED_ORIGINS` 只含显式 HTTPS origin，禁止通配符、localhost、占位域名、path、query 和 fragment。
3. `CorsBoundaryContractTest` 直接执行真实 `CorsFilter`：非白名单 Origin 在进入 Controller 前返回 403；白名单 Origin 精确回显并允许凭据；预检请求不进入业务代码；源码扫描保证局部注解为 0。
4. `production-smoke.sh` 要求提供一个真实白名单 Origin，同时以固定非白名单 Origin 验证拒绝分支，整个过程只执行 GET/OPTIONS 语义，不写业务数据。

## 边界

- 微信小程序原生请求不依赖浏览器 CORS，不需要把微信域名加入该白名单。
- Admin 与公开报告 H5 的正式 origin 必须分别列入；API 自身域名不是前端页面 origin 时不自动加入。
- 临时联调域名不得直接写入 Controller；必须通过受控环境配置、评审和生产 preflight。
