init: consolidate all ephron.ren PRDs and docs

This commit is contained in:
Ubuntu
2026-05-15 10:39:54 +08:00
parent 9568533314
commit ee8cddf8b8
21 changed files with 6991 additions and 2 deletions

View File

@@ -0,0 +1,119 @@
# Bug 修复方案:集合编辑页面文章无法勾选
## 问题描述
**页面**`https://blog.ephron.ren/admin/collections/edit/{key}`
**现象**点击文章列表中的文章项checkbox 不会被勾选,已选文章区域也不会更新。
**影响范围**
- 集合编辑页面collection_edit.html— 无法勾选文章
- 集合新建页面collection_new.html— 同样受影响
- 集合管理列表页admin/collections.html— 同样受影响
---
## 根因分析
### 直接原因
`blog/templates/base.html` **缺少 `{% block extra_scripts %}` 定义**
### 详细分析
1. `collection_edit.html` 第 261 行声明了:
```html
{% block extra_scripts %}
<script>
(() => {
// 文章选择逻辑togglePost、renderSelected、拖拽排序等
})();
</script>
{% endblock %}
```
2. 但 `base.html` 的模板结构只有:
```html
{% block extra_styles %}{% endblock %} ✅ 存在
{% block content %}{% endblock %} ✅ 存在
{% block extra_scripts %}{% endblock %} ❌ 缺失
```
3. 由于 `base.html` 未定义 `extra_scripts` blockJinja2 **直接忽略**子模板中该 block 的内容,导致整个文章选择的 JavaScript 代码**根本没有被渲染到页面**。
### 对比其他服务
| 服务 | base 模板 | extra_scripts 定义 |
|------|----------|------------------|
| blog | `blog/templates/base.html` | ❌ 缺失 |
| prompt | `prompt/templates/base.html` | ✅ 已有 |
| auth | `auth/templates/_design_system/page_shell.html` | ✅ 已有 |
| canvas | `canvas/templates/base.html` | ✅ 已有 |
| home | `home/templates/_design_system/page_shell.html` | ✅ 已有 |
---
## 修复方案
### 修改文件
`blog/templates/base.html`
### 修改内容
在 `</body>` 标签前添加 `{% block extra_scripts %}{% endblock %}`。
**修改前**(第 663-664 行):
```html
</script>
</body>
</html>
```
**修改后**
```html
</script>
{% block extra_scripts %}{% endblock %}
</body>
</html>
```
### 完整 Diff
```diff
--- a/blog/templates/base.html
+++ b/blog/templates/base.html
@@ -661,5 +661,6 @@
});
});
</script>
+ {% block extra_scripts %}{% endblock %}
</body>
</html>
```
---
## 验证方法
1. 部署后访问 `https://blog.ephron.ren/admin/collections/edit/{key}`
2. 点击文章列表中的任意文章项
3. 预期checkbox 被勾选,文章出现在「已选文章」区域
4. 再次点击同一文章
5. 预期checkbox 取消勾选,文章从「已选文章」区域移除
6. 点击「保存更新」
7. 预期:页面刷新后,之前勾选的文章仍然显示在「已选文章」区域
---
## 影响评估
- **风险等级**:低(纯新增 block 定义,不影响现有逻辑)
- **影响范围**blog 服务所有使用 `extra_scripts` block 的页面
- **回滚方案**:删除添加的一行即可
---
## 优先级
**高** — 集合编辑功能完全不可用,需要立即修复。

104
fixes/login-redirect-fix.md Normal file
View File

@@ -0,0 +1,104 @@
# ephron.ren 登录重定向失效修复方案
## 问题描述
在主页www.ephron.ren未登录状态下点击右上角「未登录」跳转至登录页输入账号密码点击登录后页面不会自动重定向回主页而是停留在登录页。
## 影响范围
所有子服务Home / Blog / Canvas / Prompt的登录后重定向均受影响。只要登录页 URL 中带有 `redirect` 参数指向其他子域名,登录后都无法跳转。
## 根因分析
### 直接原因
Chrome 浏览器的 CSPContent 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
<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`
```diff
- <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`
```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 fieldbody |
| CSP 检查 | action URL 含 `//` → 误判为跨域 → 拦截 | action URL 为纯路径 → 同源 → 放行 |
### 不受影响的部分
- 登录页 GET 请求传递 redirect 参数query string不受影响CSP `form-action` 只拦截 POST
- 登录失败时重定向回登录页(携带 redirect 参数)不受影响,因为那是 303 跳转,不是表单提交
- `validate_redirect()` 安全校验逻辑无需修改
- cookie 设置逻辑无需修改