update
This commit is contained in:
parent
ab7fa6b895
commit
f1b6f56f3e
@ -197,7 +197,9 @@ async def password_login(
|
||||
request: Request = None
|
||||
):
|
||||
"""密码登录"""
|
||||
print(f"login_data: {login_data}")
|
||||
user = db.query(UserDB).filter(UserDB.phone == login_data.phone).first()
|
||||
print(f"user: {user}")
|
||||
|
||||
if not user:
|
||||
return error_response(code=401, message="用户不存在")
|
||||
|
||||
@ -3,20 +3,51 @@ from app.models.database import SessionLocal
|
||||
from app.models.request_log import RequestLogDB
|
||||
import json
|
||||
from threading import Thread
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
|
||||
def save_request_log(log_data: Dict[str, Any]):
|
||||
"""保存请求日志到数据库"""
|
||||
db = SessionLocal()
|
||||
db = None
|
||||
try:
|
||||
db = SessionLocal()
|
||||
|
||||
# 确保headers和body可以序列化为JSON
|
||||
if 'headers' in log_data and log_data['headers']:
|
||||
try:
|
||||
# 尝试将headers转换为JSON字符串再解析回来,确保可序列化
|
||||
json.dumps(log_data['headers'])
|
||||
except (TypeError, OverflowError):
|
||||
# 如果无法序列化,则转换为字符串
|
||||
log_data['headers'] = str(log_data['headers'])
|
||||
|
||||
if 'body' in log_data and log_data['body']:
|
||||
try:
|
||||
# 尝试将body转换为JSON字符串再解析回来,确保可序列化
|
||||
json.dumps(log_data['body'])
|
||||
except (TypeError, OverflowError):
|
||||
# 如果无法序列化,则转换为字符串
|
||||
log_data['body'] = str(log_data['body'])
|
||||
|
||||
# 创建日志记录
|
||||
log = RequestLogDB(**log_data)
|
||||
db.add(log)
|
||||
db.commit()
|
||||
print(f"请求日志已保存: {log_data['path']}")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
print(f"保存日志失败: {str(e)}")
|
||||
print(traceback.format_exc())
|
||||
if db:
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
if db:
|
||||
db.close()
|
||||
|
||||
def log_request_async(log_data: Dict[str, Any]):
|
||||
"""在新线程中异步处理日志"""
|
||||
Thread(target=save_request_log, args=(log_data,), daemon=True).start()
|
||||
try:
|
||||
Thread(target=save_request_log, args=(log_data,), daemon=True).start()
|
||||
except Exception as e:
|
||||
print(f"启动日志线程失败: {str(e)}")
|
||||
print(traceback.format_exc())
|
||||
@ -26,7 +26,6 @@ def verify_token(token: str) -> Optional[str]:
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
|
||||
sub: str = payload.get("sub")
|
||||
print(f"payload: {payload}")
|
||||
return sub
|
||||
except JWTError:
|
||||
return None
|
||||
|
||||
@ -5,6 +5,12 @@ from app.core.logger import log_request_async
|
||||
from app.core.security import verify_token, decode_jwt
|
||||
import json
|
||||
import copy
|
||||
import asyncio
|
||||
from starlette.responses import JSONResponse
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
class RequestLoggerMiddleware(BaseHTTPMiddleware):
|
||||
LOGGED_METHODS = {"POST", "PUT", "DELETE"}
|
||||
@ -26,6 +32,17 @@ class RequestLoggerMiddleware(BaseHTTPMiddleware):
|
||||
filtered_data[field] = "***"
|
||||
return filtered_data
|
||||
|
||||
def filter_headers(self, headers: dict) -> dict:
|
||||
"""过滤敏感请求头"""
|
||||
filtered_headers = copy.deepcopy(headers)
|
||||
sensitive_headers = ["authorization", "cookie"]
|
||||
|
||||
for header in sensitive_headers:
|
||||
if header in filtered_headers:
|
||||
filtered_headers[header] = "***"
|
||||
|
||||
return filtered_headers
|
||||
|
||||
async def dispatch(self, request: Request, call_next):
|
||||
method = request.method
|
||||
|
||||
@ -34,54 +51,65 @@ class RequestLoggerMiddleware(BaseHTTPMiddleware):
|
||||
|
||||
start_time = time.time()
|
||||
path = request.url.path
|
||||
headers = dict(request.headers)
|
||||
|
||||
# 不记录健康检查请求
|
||||
if path.endswith("/health") or path.endswith("/ping"):
|
||||
return await call_next(request)
|
||||
|
||||
# 过滤敏感请求头
|
||||
headers = self.filter_headers(dict(request.headers))
|
||||
query_params = dict(request.query_params)
|
||||
|
||||
# 获取并过滤请求体
|
||||
# 创建请求体的副本,而不消费原始请求体
|
||||
body = None
|
||||
try:
|
||||
# 保存原始请求体内容
|
||||
body_bytes = await request.body()
|
||||
|
||||
# 重要:设置_body属性,使FastAPI可以再次读取请求体
|
||||
request._body = body_bytes
|
||||
|
||||
if body_bytes:
|
||||
body = json.loads(body_bytes)
|
||||
body = self.filter_sensitive_data(body, path)
|
||||
print(f"请求体: {body}")
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
body_str = body_bytes.decode()
|
||||
body = json.loads(body_str)
|
||||
body = self.filter_sensitive_data(body, path)
|
||||
except json.JSONDecodeError:
|
||||
body = {"raw": "无法解析的JSON数据"}
|
||||
except UnicodeDecodeError:
|
||||
body = {"raw": "无法解码的二进制数据"}
|
||||
except Exception as e:
|
||||
logger.error(f"读取请求体异常: {str(e)}")
|
||||
body = {"error": "读取请求体异常"}
|
||||
|
||||
# 从 Authorization 头获取 token
|
||||
# token = None
|
||||
# auth_header = headers.get('authorization')
|
||||
# if auth_header and auth_header.startswith('Bearer '):
|
||||
# token = auth_header.split(' ')[1]
|
||||
|
||||
# # 从 token 获取用户信息
|
||||
# user_id = None
|
||||
# if token:
|
||||
# try:
|
||||
# payload = decode_jwt(token)
|
||||
# if payload:
|
||||
# user_id = payload.get("phone")
|
||||
# except:
|
||||
# pass
|
||||
|
||||
# 处理请求
|
||||
response = await call_next(request)
|
||||
|
||||
# 计算响应时间
|
||||
response_time = int((time.time() - start_time) * 1000)
|
||||
|
||||
# 异步记录日志
|
||||
log_data = {
|
||||
"path": path,
|
||||
"method": method,
|
||||
"headers": headers,
|
||||
"query_params": query_params,
|
||||
"body": body,
|
||||
# "user_id": user_id,
|
||||
"ip_address": request.client.host,
|
||||
"status_code": response.status_code,
|
||||
"response_time": response_time
|
||||
}
|
||||
log_request_async(log_data)
|
||||
|
||||
return response
|
||||
# 处理请求,添加超时保护
|
||||
try:
|
||||
response = await call_next(request)
|
||||
|
||||
# 计算响应时间
|
||||
response_time = int((time.time() - start_time) * 1000)
|
||||
|
||||
# 异步记录日志,捕获可能的异常
|
||||
try:
|
||||
log_data = {
|
||||
"path": path,
|
||||
"method": method,
|
||||
"headers": headers,
|
||||
"query_params": query_params,
|
||||
"body": body,
|
||||
"ip_address": request.client.host if hasattr(request, "client") and request.client else "unknown",
|
||||
"status_code": response.status_code,
|
||||
"response_time": response_time
|
||||
}
|
||||
log_request_async(log_data)
|
||||
except Exception as e:
|
||||
logger.error(f"记录请求日志异常: {str(e)}")
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"请求处理异常: {str(e)}")
|
||||
return JSONResponse(
|
||||
status_code=500,
|
||||
content={"code": 500, "message": "服务器内部错误"}
|
||||
)
|
||||
@ -112,9 +112,9 @@ class UserUpdate(BaseModel):
|
||||
extra = "forbid" # 禁止额外字段
|
||||
|
||||
class UserPasswordLogin(BaseModel):
|
||||
phone: str = Field(..., pattern="^1[3-9]\d{9}$")
|
||||
password: str = Field(..., min_length=6, max_length=20)
|
||||
role: UserRole = Field(default=UserRole.DELIVERYMAN)
|
||||
phone: str = Field(..., pattern="^1[3-9]\d{9}$", description="手机号")
|
||||
password: str = Field(..., min_length=6, max_length=20, description="密码")
|
||||
role: UserRole = Field(default=UserRole.ADMIN, description="角色")
|
||||
|
||||
class ChangePasswordRequest(BaseModel):
|
||||
phone: str = Field(..., pattern="^1[3-9]\d{9}$")
|
||||
|
||||
BIN
jobs.sqlite
BIN
jobs.sqlite
Binary file not shown.
Loading…
Reference in New Issue
Block a user