3.7 KiB
3.7 KiB
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 中:
<form method="POST" action="/api/login?redirect=https%3A//www.ephron.ren/">
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
- <form class="login-form" method="POST" action="/api/login{% if redirect %}?redirect={{ redirect | urlencode }}{% endif %}">
+ <form class="login-form" method="POST" action="/api/login">
{% if error %}
<div class="alert alert-error">
{{ error }}
</div>
{% endif %}
+ {% if redirect %}
+ <input type="hidden" name="redirect" value="{{ redirect }}">
+ {% endif %}
+
<div class="form-group">
<label for="username">用户名</label>
修改文件 2:auth/src/routes/api.py
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 设置逻辑无需修改