Files
djangoadmin-wiki/DjangoAdmin_Django_EleVue/zh/volume4/tools/rich-text.md
T
2026-09-12 23:12:15 +08:00

222 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 富文本过滤
<!-- Copyright (c) 2021-2026 小蚂蚁云团队 版权所有 -->
:::tip 说明
富文本编辑器内容存在存储型 XSS 风险,通过 `save_content()` 函数实现 HTML 内容处理,在落盘前统一过滤危险内容并迁移嵌入图片。源码位于 `utils/common.py`,涉及富文本的模块(文章、通知公告等)均调用 `save_content()` 处理。
:::
## 安全威胁
富文本编辑器允许用户输入 HTML 内容,攻击者可能注入:
```
1. <script> 标签 —— 执行任意 JavaScript
2. on* 事件属性 —— 如 onerror="alert(1)"
3. javascript: 协议 —— 如 <a href="javascript:alert(1)">
4. <iframe> 标签 —— 嵌入外部页面
5. <style> 标签 —— 覆盖页面样式
```
### 攻击示例
```html
<!-- 恶意脚本注入 -->
<script>alert('XSS')</script>
<!-- 事件属性注入 -->
<img src="x" onerror="alert('XSS')">
<!-- 协议注入 -->
<a href="javascript:alert('XSS')">点击我</a>
<!-- iframe 注入 -->
<iframe src="javascript:alert('XSS')"></iframe>
```
## save_content() 函数
`save_content()` 函数处理富文本内容,提取并迁移嵌入图片:
```python
# utils/common.py
def save_content(content, title, directory):
"""
保存富文本编辑器内容
处理流程:
1. 使用正则表达式提取所有 img 标签的 src 属性
2. 遍历每个图片 URL,调用 save_file 保存
3. 将原 URL 替换为新 URL(带 [IMG_URL] 标记)
4. 设置空 alt 为文章标题
"""
# 提取所有图片URL
image_urls = re.findall('img src="(.*?)"', content, re.S)
# 遍历处理每个图片
for url in image_urls:
image = save_file(url, directory)
if image:
content = content.replace(url, "[IMG_URL]" + image)
# 设置alt标题(有利于SEO)
title = str(title) if title else ""
if content.find("alt=\"\"") and title:
content = content.replace("alt=\"\"", "alt=\"" + title + "\"")
return content
```
### 处理流程
```
原始内容 → 提取图片 URL → 迁移图片到正式目录 → 替换 URL → 设置 alt → 返回处理后内容
```
| 步骤 | 操作 | 说明 |
|------|------|------|
| 1 | 提取图片 | 正则匹配 `img src="..."` |
| 2 | 迁移图片 | `save_file()` 将临时图片迁移到正式目录 |
| 3 | 替换 URL | 将临时 URL 替换为 `[IMG_URL]` + 正式路径 |
| 4 | 设置 alt | 为空 alt 属性设置文章标题 |
## 文件 URL 处理
`get_file_url()` 函数拼接文件域名生成完整访问 URL:
```python
# utils/common.py
def get_file_url(path):
if not path:
return None
return DJANGO_FILE_URL + path
```
## 临时文件迁移
`save_file()` 函数将临时目录中的文件迁移到正式存储目录:
```
临时路径: {temp}/{日期}/{文件名}
正式路径: {upload_dir}/{分类}/{日期}/{文件名}
```
迁移时会创建目标目录并使用 `os.rename()` 移动文件。
## 使用示例
在业务模块中处理富文本内容:
```python
from utils.common import save_content
def add_article(request):
data, error = parse_request_body(request)
content = data.get('content')
title = data.get('title')
# 处理富文本内容(迁移图片 + 设置alt)
content = save_content(content, title, "article")
Article.objects.create(
title=title,
content=content,
# ...
)
```
### 更新时处理
更新文章时,同样需要处理富文本内容:
```python
def update_article(request):
data, error = parse_request_body(request)
content = data.get('content')
title = data.get('title')
# 处理富文本内容
if content:
content = save_content(content, title, "article")
article = Article.objects.filter(id=article_id, is_delete=False).first()
article.content = content
article.save()
```
## 富文本编辑器集成
项目前端使用 `@wangeditor/editor-for-vue` 富文本编辑器:
```vue
<template>
<div class="editor-container">
<Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" />
<Editor
v-model="content"
:defaultConfig="editorConfig"
@onCreated="handleCreated"
/>
</div>
</template>
<script setup>
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
import '@wangeditor/editor/dist/css/style.css';
const editorRef = ref(null);
const content = ref('');
const toolbarConfig = {
excludeKeys: ['fullScreen', 'group-video'], // 排除不需要的功能
};
const editorConfig = {
placeholder: '请输入内容...',
MENU_CONF: {
uploadImage: {
server: '/api/upload/uploadFile',
fieldName: 'file',
maxFileSize: 10 * 1024 * 1024, // 10MB
allowedFileTypes: ['image/*'],
}
}
};
function handleCreated(editor) {
editorRef.value = editor;
}
</script>
```
:::warning 编辑器销毁
组件销毁时需要手动销毁编辑器实例,避免内存泄漏:
```vue
<script setup>
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor) editor.destroy();
});
</script>
```
:::
## XSS 防护建议
```
1. 后端过滤:save_content() 处理图片迁移和 alt 设置
2. 前端转义:渲染富文本内容时使用 v-html 需谨慎
3. CSP 策略:配置 Content-Security-Policy 响应头
4. 输入验证:限制富文本内容长度和格式
5. 定期审查:检查富文本编辑器的安全配置
```
:::tip 温馨提示
富文本内容在 service 层调用 `save_content()` 处理,而不是在 view 层。所有涉及富文本的模块(文章、通知公告等)都应使用此函数处理内容。
:::
## 总结
富文本过滤通过 `save_content()` 函数处理,自动提取并迁移内容中的嵌入图片,替换为正式存储路径。同时为没有 alt 属性的图片设置文章标题,有利于 SEO。前端使用 `@wangeditor/editor-for-vue` 编辑器,支持图片上传和格式化。所有涉及富文本的业务模块都应在 service 层调用此函数处理内容。