## 问题 当前后端已挂载 `CORSMiddleware`,但受保护接口的跨域预检请求仍会被 `AuthMiddleware` 提前拦截。 浏览器发送预检 `OPTIONS` 时不会携带 Bearer token。后端因此返回 HTTP 200 + 业务码 401,且响应缺少 `access-control-allow-*` 头,浏览器不会继续发送实际的 GET、PATCH 或 POST 请求。 这会阻断所有前后端分域部署下的受保护接口,不只影响账号中心。 ## 复现证据 在最新 `main`(`efd230e`)配置: `WINDUP_CORS_ORIGINS=https://frontend.example` 实际中间件顺序: `RateLimitMiddleware → AuthMiddleware → CORSMiddleware` | Preflight | Result | | --- | --- | | `POST /auth/login` | 正常返回 `OK`,包含允许来源、方法和请求头 | | `GET /auth/me` | 返回业务码 401,缺少全部 CORS 响应头 | | `PATCH /auth/profile` | 返回业务码 401,缺少全部 CORS 响应头 | | `POST /auth/change-password` | 返回业务码 401,缺少全部 CORS 响应头 | | `GET /projects` | 返回业务码 401,缺少全部 CORS 响应头 | ## 根因 `create_app()` 先注册 `CORSMiddleware`,随后注册 `AuthMiddleware` 与 `RateLimitMiddleware`。按当前 Starlette 中间件装配顺序,后注册的中间件先收到请求,因此鉴权发生在 CORS 之前。 `AuthMiddleware` 只按路径白名单放行请求,没有单独放行 `OPTIONS`。受保护路径的预检没有 Authorization header,于是在到达 CORS 中间件前被返回“未登录”。 该顺序随 #149 的认证中间件注册进入主线。#139 处理的是“完全未挂 CORS”,#143 处理的是另一分支上的来源配置问题,均未覆盖受保护路径的预检顺序。 ## 预期行为 - 已配置来源发出的合法预检请求应由 CORS 层处理,不要求 Bearer token。 - 预检成功后,实际受保护请求仍必须通过现有 JWT 鉴权。 - 未配置的来源不得获得 `access-control-allow-origin`。 - 公共认证接口行为保持不变。 ## 验收标准 - [ ] `GET`、`PATCH`、`POST` 类型的受保护接口预检均能正常返回 CORS 响应头。 - [ ] 预检请求不要求 Authorization header。 - [ ] 不带 token 的实际受保护请求仍返回现有业务码 401。 - [ ] 未配置来源仍无法通过预检。 - [ ] 增加自动化回归测试,同时覆盖公共接口与受保护接口的预检差异。 - [ ] 浏览器可跨域调用 `/auth/me`、`/auth/profile`、`/auth/change-password` 和 `/projects`。 ## Scope - 本 Issue 只修复 CORS 与鉴权中间件的请求顺序或预检放行逻辑,并补充测试。 - 不调整 JWT、业务权限、允许来源策略或前端账号中心代码。 ## Related Issues Refs #139 Refs #143 Refs #149 Refs #161 Refs #183
Activity
fix(middleware): 调整 CORS 中间件顺序,修复预检请求被 AuthMiddleware 拦截 (1024XEngine…