v0.1测试
This commit is contained in:
121
backend/middleware/sanitize.py
Normal file
121
backend/middleware/sanitize.py
Normal file
@@ -0,0 +1,121 @@
|
||||
# ===========================================
|
||||
# 班级操行分管理系统 - 后端服务
|
||||
#
|
||||
# 开发者: Canglan
|
||||
# 联系方式: admin@sea-studio.top
|
||||
# 版权归属: Sea Network Technology Studio
|
||||
# 许可证: MIT License
|
||||
#
|
||||
# 版权所有 © Sea Network Technology Studio
|
||||
# ===========================================
|
||||
|
||||
from fastapi import Request
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from typing import Dict, Any
|
||||
import re
|
||||
|
||||
|
||||
class SanitizeMiddleware(BaseHTTPMiddleware):
|
||||
"""输入过滤中间件"""
|
||||
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
# 只处理POST、PUT、PATCH请求
|
||||
if request.method in ["POST", "PUT", "PATCH"]:
|
||||
# 获取请求体
|
||||
body = await request.body()
|
||||
if body:
|
||||
import json
|
||||
try:
|
||||
data = json.loads(body)
|
||||
# 清理数据
|
||||
cleaned_data = self._sanitize_data(data)
|
||||
# 替换请求体
|
||||
request._body = json.dumps(cleaned_data).encode()
|
||||
except:
|
||||
pass
|
||||
|
||||
response = await call_next(request)
|
||||
return response
|
||||
|
||||
def _sanitize_data(self, data: Any) -> Any:
|
||||
"""递归清理数据"""
|
||||
if isinstance(data, dict):
|
||||
return {k: self._sanitize_data(v) for k, v in data.items()}
|
||||
elif isinstance(data, list):
|
||||
return [self._sanitize_data(item) for item in data]
|
||||
elif isinstance(data, str):
|
||||
return self._sanitize_string(data)
|
||||
else:
|
||||
return data
|
||||
|
||||
def _sanitize_string(self, value: str) -> str:
|
||||
"""清理字符串"""
|
||||
if not value:
|
||||
return ""
|
||||
|
||||
# 去除首尾空格
|
||||
value = value.strip()
|
||||
|
||||
# 限制长度
|
||||
if len(value) > 1000:
|
||||
value = value[:1000]
|
||||
|
||||
# 转义HTML特殊字符
|
||||
html_chars = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
}
|
||||
for char, escape in html_chars.items():
|
||||
value = value.replace(char, escape)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def sanitize_input(value: str, max_length: int = 255) -> str:
|
||||
"""清理单个输入值"""
|
||||
if not value:
|
||||
return ""
|
||||
|
||||
value = value.strip()
|
||||
if len(value) > max_length:
|
||||
value = value[:max_length]
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def validate_points(points: int, min_val: int = -100, max_val: int = 100) -> tuple:
|
||||
"""
|
||||
验证分值
|
||||
返回: (是否有效, 错误信息)
|
||||
"""
|
||||
if points == 0:
|
||||
return False, "分值不能为0"
|
||||
if points < min_val or points > max_val:
|
||||
return False, f"分值必须在{min_val}到{max_val}之间"
|
||||
return True, ""
|
||||
|
||||
|
||||
def validate_reason(reason: str) -> tuple:
|
||||
"""
|
||||
验证原因
|
||||
返回: (是否有效, 错误信息)
|
||||
"""
|
||||
if not reason or not reason.strip():
|
||||
return False, "原因不能为空"
|
||||
if len(reason) > 255:
|
||||
return False, "原因长度不能超过255个字符"
|
||||
return True, ""
|
||||
|
||||
|
||||
def validate_date(date_str: str) -> bool:
|
||||
"""验证日期格式 YYYY-MM-DD"""
|
||||
if not date_str:
|
||||
return False
|
||||
pattern = r'^\d{4}-\d{2}-\d{2}$'
|
||||
if not re.match(pattern, date_str):
|
||||
return False
|
||||
return True
|
||||
Reference in New Issue
Block a user