# ephron.ren 登录重定向失效修复方案 ## 问题描述 在主页(www.ephron.ren)未登录状态下,点击右上角「未登录」跳转至登录页,输入账号密码点击登录后,页面不会自动重定向回主页,而是停留在登录页。 ## 影响范围 所有子服务(Home / Blog / Canvas / Prompt)的登录后重定向均受影响。只要登录页 URL 中带有 `redirect` 参数指向其他子域名,登录后都无法跳转。 ## 根因分析 ### 直接原因 Chrome 浏览器的 CSP(Content Security Policy)引擎将登录表单的 POST 请求拦截了。 浏览器控制台报错: ``` Sending form data to 'https://auth.ephron.ren/api/login?redirect=https%3A//www.ephron.ren/' violates the following Content Security Policy directive: "form-action 'self'". The request has been blocked. ``` ### 技术细节 站点响应头中设置了 CSP: ``` form-action 'self' ``` 该指令限制表单只能提交到同源 URL。 **问题在于**:登录表单将 `redirect` 参数拼接在 form action 的 query string 中: ```html
``` Chrome 的 CSP 引擎在解析 form action URL 时,会将 query string 中的 `%3A` 解码为 `:`,使得 `://` 看起来像协议标识符。引擎误判该 URL 包含跨域目标(`https://www.ephron.ren/`),从而拦截了表单提交。 ### 验证证据 | 场景 | form action | 结果 | |------|------------|------| | 不带 redirect 参数 | `/api/login` | ✅ 登录成功,跳转到 `/login-success` | | 带 redirect 到自身域名 | `/api/login?redirect=https%3A//auth.ephron.ren/admin` | ✅ 正常 | | 带 redirect 到其他子域名 | `/api/login?redirect=https%3A//www.ephron.ren/` | ❌ CSP 拦截 | ## 修复方案 将 `redirect` 参数从 URL query string 改为表单 hidden field,使 form action 保持干净,不含任何可能触发 CSP 误判的字符。 ### 修改文件 1:`auth/templates/login.html` ```diff - + {% if error %}
{{ error }}
{% endif %} + {% if redirect %} + + {% endif %} +
``` ### 修改文件 2:`auth/src/routes/api.py` ```diff async def login( request: Request, username: str = Form(...), password: str = Form(...), - redirect: str | None = Query(default=None), - return_url: str | None = Query(default=None, alias="return_url"), - next_url: str | None = Query(default=None, alias="next"), + redirect: str | None = Form(default=None), + return_url: str | None = Form(default=None), + next_url: str | None = Form(default=None), ): ``` ### 修复原理 | | 修改前 | 修改后 | |--|--------|--------| | form action | `/api/login?redirect=https%3A//www.ephron.ren/` | `/api/login` | | redirect 传递方式 | URL query string | hidden form field(body) | | CSP 检查 | action URL 含 `//` → 误判为跨域 → 拦截 | action URL 为纯路径 → 同源 → 放行 | ### 不受影响的部分 - 登录页 GET 请求传递 redirect 参数(query string)不受影响,CSP `form-action` 只拦截 POST - 登录失败时重定向回登录页(携带 redirect 参数)不受影响,因为那是 303 跳转,不是表单提交 - `validate_redirect()` 安全校验逻辑无需修改 - cookie 设置逻辑无需修改