加密后
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
import json
|
||||
from functools import wraps
|
||||
|
||||
from encryption.encryption import aes_encrypt
|
||||
from schema.response_schema import APIResponse
|
||||
from utils.encrypt_utils import aes_encrypt
|
||||
|
||||
|
||||
def encrypt_response(field: str = "data"):
|
||||
|
||||
@ -2,6 +2,7 @@ from fastapi import APIRouter, Query, Path
|
||||
from mysql.connector import Error as MySQLError
|
||||
|
||||
from ds.db import db
|
||||
from encryption.encrypt_decorator import encrypt_response
|
||||
from schema.device_action_schema import (
|
||||
DeviceActionCreate,
|
||||
DeviceActionResponse,
|
||||
@ -62,6 +63,7 @@ def add_device_action(action_data: DeviceActionCreate) -> DeviceActionResponse:
|
||||
# 接口: 分页查询操作记录列表(仅返回 total + device_actions)
|
||||
# ------------------------------
|
||||
@router.get("/list", response_model=APIResponse, summary="分页查询设备操作记录")
|
||||
@encrypt_response()
|
||||
async def get_device_action_list(
|
||||
page: int = Query(1, ge=1, description="页码、默认1"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="每页条数、1-100"),
|
||||
@ -119,6 +121,7 @@ async def get_device_action_list(
|
||||
|
||||
|
||||
@router.get("/{client_ip}", response_model=APIResponse, summary="根据IP查询设备操作记录")
|
||||
@encrypt_response()
|
||||
async def get_device_actions_by_ip(
|
||||
client_ip: str = Path(..., description="客户端IP地址")
|
||||
):
|
||||
|
||||
@ -5,6 +5,7 @@ from fastapi import APIRouter, Query, HTTPException, Request, Path
|
||||
from mysql.connector import Error as MySQLError
|
||||
|
||||
from ds.db import db
|
||||
from encryption.encrypt_decorator import encrypt_response
|
||||
from schema.device_schema import (
|
||||
DeviceCreateRequest, DeviceResponse, DeviceListResponse,
|
||||
DeviceStatusHistoryResponse, DeviceStatusHistoryListResponse
|
||||
@ -161,6 +162,7 @@ def update_online_status_by_ip(client_ip: str, online_status: int) -> bool:
|
||||
# 创建设备信息接口
|
||||
# ------------------------------
|
||||
@router.post("/add", response_model=APIResponse, summary="创建设备信息")
|
||||
@encrypt_response()
|
||||
async def create_device(device_data: DeviceCreateRequest, request: Request):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -242,6 +244,7 @@ async def create_device(device_data: DeviceCreateRequest, request: Request):
|
||||
# 获取设备列表接口
|
||||
# ------------------------------
|
||||
@router.get("/", response_model=APIResponse, summary="获取设备列表(支持筛选分页)")
|
||||
@encrypt_response()
|
||||
async def get_device_list(
|
||||
page: int = Query(1, ge=1, description="页码,默认第1页"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="每页条数,1-100之间"),
|
||||
@ -301,6 +304,7 @@ async def get_device_list(
|
||||
# 获取设备上下线记录接口
|
||||
# ------------------------------
|
||||
@router.get("/{device_id}/status-history", response_model=APIResponse, summary="获取设备上下线记录")
|
||||
@encrypt_response()
|
||||
async def get_device_status_history(
|
||||
device_id: int = Path(..., description="设备ID"),
|
||||
page: int = Query(1, ge=1, description="页码,默认第1页"),
|
||||
@ -380,6 +384,7 @@ async def get_device_status_history(
|
||||
# 手动更新设备在线状态接口
|
||||
# ------------------------------
|
||||
@router.put("/{device_id}/status", response_model=APIResponse, summary="更新设备在线状态")
|
||||
@encrypt_response()
|
||||
async def update_device_status(
|
||||
device_id: int = Path(..., description="设备ID"),
|
||||
status: int = Query(..., ge=0, le=1, description="在线状态(1-在线、0-离线)")
|
||||
|
||||
@ -5,6 +5,7 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
from ds.db import db
|
||||
from encryption.encrypt_decorator import encrypt_response
|
||||
from schema.face_schema import (
|
||||
FaceCreateRequest,
|
||||
FaceUpdateRequest,
|
||||
@ -23,6 +24,7 @@ router = APIRouter(prefix="/faces", tags=["人脸管理"])
|
||||
# 1. 创建人脸记录(使用修复后的路径)
|
||||
# ------------------------------
|
||||
@router.post("", response_model=APIResponse, summary="创建人脸记录")
|
||||
@encrypt_response()
|
||||
async def create_face(
|
||||
request: Request,
|
||||
name: str = Form(None, max_length=255, description="名称(可选)"),
|
||||
@ -97,6 +99,7 @@ async def create_face(
|
||||
# 2. 获取单个人脸记录
|
||||
# ------------------------------
|
||||
@router.get("/{face_id}", response_model=APIResponse, summary="获取单个人脸记录")
|
||||
@encrypt_response()
|
||||
async def get_face(face_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -130,6 +133,7 @@ async def get_face(face_id: int):
|
||||
# 3. 获取人脸列表
|
||||
# ------------------------------
|
||||
@router.get("", response_model=APIResponse, summary="获取人脸列表(分页+筛选)")
|
||||
@encrypt_response()
|
||||
async def get_face_list(
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(10, ge=1, le=100),
|
||||
@ -189,6 +193,7 @@ async def get_face_list(
|
||||
# 4. 更新人脸记录
|
||||
# ------------------------------
|
||||
@router.put("/{face_id}", response_model=APIResponse, summary="更新人脸记录")
|
||||
@encrypt_response()
|
||||
async def update_face(face_id: int, face_update: FaceUpdateRequest):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -255,6 +260,7 @@ async def update_face(face_id: int, face_update: FaceUpdateRequest):
|
||||
# 5. 删除人脸记录
|
||||
# ------------------------------
|
||||
@router.delete("/{face_id}", response_model=APIResponse, summary="删除人脸记录")
|
||||
@encrypt_response()
|
||||
async def delete_face(face_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -305,6 +311,7 @@ async def delete_face(face_id: int):
|
||||
# 6. 获取人脸图片
|
||||
# ------------------------------
|
||||
@router.get("/{face_id}/image", summary="获取人脸图片")
|
||||
@encrypt_response()
|
||||
async def get_face_image(face_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
|
||||
@ -18,12 +18,11 @@ app = Flask(__name__)
|
||||
# ------------------------------
|
||||
# 核心修改:与 FastAPI 对齐的跨域配置
|
||||
# ------------------------------
|
||||
# 1. 允许的前端域名(完全复制 FastAPI 的 ALLOWED_ORIGINS,确保前后端一致)
|
||||
# 1. 允许的前端域名(根据实际环境修改,生产环境删除 "*")
|
||||
ALLOWED_ORIGINS = [
|
||||
# "http://localhost:8080", # 本地前端开发地址(必改:替换为你的前端实际地址)
|
||||
# "http://localhost:8080", # 本地前端开发地址
|
||||
# "http://127.0.0.1:8080",
|
||||
# "http://服务器IP:8080", # 部署后前端地址(替换为你的服务器IP/域名)
|
||||
# # "*" 仅开发环境临时使用,生产环境必须删除(安全风险)
|
||||
# "http://服务器IP:8080", # 部署后前端地址
|
||||
"*"
|
||||
]
|
||||
|
||||
@ -31,33 +30,29 @@ ALLOWED_ORIGINS = [
|
||||
CORS(
|
||||
app,
|
||||
resources={
|
||||
r"/*": { # 对所有 Flask 路由生效(覆盖图片、模型下载所有接口)
|
||||
"origins": ALLOWED_ORIGINS, # 允许的前端域名(与 FastAPI 一致)
|
||||
"allow_credentials": True, # 允许携带 Cookie(与 FastAPI 一致,需登录态必开)
|
||||
"methods": ["*"], # 允许所有 HTTP 方法(FastAPI 用 "*",此处同步)
|
||||
"allow_headers": ["*"], # 允许所有请求头(与 FastAPI 一致)
|
||||
r"/*": {
|
||||
"origins": ALLOWED_ORIGINS,
|
||||
"allow_credentials": True,
|
||||
"methods": ["*"],
|
||||
"allow_headers": ["*"],
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
# ------------------------------
|
||||
# 核心路径配置(不变,确保资源目录正确)
|
||||
# 核心路径配置(关键修改:修正 PROJECT_ROOT 计算)
|
||||
# 原问题:file_service.py 在 service 文件夹内,需向上跳一级到项目根目录
|
||||
# ------------------------------
|
||||
CURRENT_FILE_PATH = Path(__file__).resolve()
|
||||
PROJECT_ROOT = CURRENT_FILE_PATH.parent # 项目根目录(video/)
|
||||
# 资源目录(图片、模型)
|
||||
BASE_IMAGE_DIR_DECT = str((PROJECT_ROOT / "resource" / "dect").resolve()) # 检测图片目录
|
||||
BASE_IMAGE_DIR_UP_IMAGES = str((PROJECT_ROOT / "up_images").resolve()) # 人脸图片目录
|
||||
BASE_MODEL_DIR = str((PROJECT_ROOT / "resource" / "models").resolve()) # 模型文件目录
|
||||
CURRENT_FILE_PATH = Path(__file__).resolve() # 当前文件路径:service/file_service.py
|
||||
PROJECT_ROOT = CURRENT_FILE_PATH.parent.parent # 项目根目录(service 文件夹的父目录)
|
||||
# 资源目录(现在正确指向项目根目录下的文件夹)
|
||||
BASE_IMAGE_DIR_DECT = str((PROJECT_ROOT / "resource" / "dect").resolve()) # 根目录/resource/dect
|
||||
BASE_IMAGE_DIR_UP_IMAGES = str((PROJECT_ROOT / "up_images").resolve()) # 根目录/up_images
|
||||
BASE_MODEL_DIR = str((PROJECT_ROOT / "resource" / "models").resolve()) # 根目录/resource/models
|
||||
|
||||
# 打印路径配置(调试用,确认目录正确)
|
||||
# logger.info(f"[Flask 配置] 项目根目录:{PROJECT_ROOT}")
|
||||
# logger.info(f"[Flask 配置] 模型目录:{BASE_MODEL_DIR}")
|
||||
# logger.info(f"[Flask 配置] 人脸图片目录:{BASE_IMAGE_DIR_UP_IMAGES}")
|
||||
# logger.info(f"[Flask 配置] 检测图片目录:{BASE_IMAGE_DIR_DECT}")
|
||||
|
||||
# ------------------------------
|
||||
# 安全检查装饰器(不变,防路径遍历/非法文件)
|
||||
# 安全检查装饰器(不变)
|
||||
# ------------------------------
|
||||
def safe_path_check(root_dir: str):
|
||||
def decorator(func):
|
||||
@ -86,7 +81,7 @@ def safe_path_check(root_dir: str):
|
||||
)
|
||||
abort(404)
|
||||
|
||||
# 3. 限制文件大小(模型200MB,图片10MB,避免超大文件攻击)
|
||||
# 3. 限制文件大小(模型200MB,图片10MB)
|
||||
max_size = 200 * 1024 * 1024 if "models" in root_dir else 10 * 1024 * 1024
|
||||
if os.path.getsize(full_file_path) > max_size:
|
||||
logger.warning(
|
||||
@ -121,7 +116,7 @@ def download_model(resource_path, root_dir):
|
||||
f"[Flask 模型下载] 成功请求!IP:{request.remote_addr} | 文件:{file_name} | 目录:{full_dir}"
|
||||
)
|
||||
|
||||
# 强制浏览器下载(而非预览),设置二进制文件类型
|
||||
# 强制浏览器下载(而非预览)
|
||||
return send_from_directory(
|
||||
full_dir,
|
||||
file_name,
|
||||
@ -158,7 +153,7 @@ def get_face_image(resource_path, root_dir):
|
||||
f"[Flask 人脸图片] 成功请求!IP:{request.remote_addr} | 文件:{file_name} | 目录:{full_dir}"
|
||||
)
|
||||
|
||||
# 允许浏览器预览图片(而非下载)
|
||||
# 允许浏览器预览图片
|
||||
return send_from_directory(full_dir, file_name, as_attachment=False)
|
||||
|
||||
except Exception as e:
|
||||
@ -205,7 +200,6 @@ def get_dect_image(resource_path, root_dir):
|
||||
@safe_path_check(root_dir=BASE_IMAGE_DIR_DECT)
|
||||
def get_compatible_image(resource_path, root_dir):
|
||||
try:
|
||||
# 逻辑与检测图片接口一致,仅URL前缀不同(兼容旧前端)
|
||||
resource_path = resource_path.replace("/", os.sep).replace("\\", os.sep)
|
||||
dir_path, file_name = os.path.split(resource_path)
|
||||
full_dir = os.path.abspath(os.path.join(root_dir, dir_path))
|
||||
@ -230,7 +224,7 @@ def get_compatible_image(resource_path, root_dir):
|
||||
abort(500)
|
||||
|
||||
# ------------------------------
|
||||
# 全局错误处理器(友好提示,与 FastAPI 错误信息风格一致)
|
||||
# 全局错误处理器(不变)
|
||||
# ------------------------------
|
||||
@app.errorhandler(403)
|
||||
def forbidden_error(error):
|
||||
@ -256,7 +250,7 @@ def server_error(error):
|
||||
# Flask 独立启动入口(供测试,实际由 main.py 子线程启动)
|
||||
# ------------------------------
|
||||
if __name__ == '__main__':
|
||||
# 确保所有资源目录存在(防止初始化失败)
|
||||
# 确保所有资源目录存在
|
||||
required_dirs = [
|
||||
(BASE_IMAGE_DIR_DECT, "检测图片目录"),
|
||||
(BASE_IMAGE_DIR_UP_IMAGES, "人脸图片目录"),
|
||||
@ -267,16 +261,16 @@ if __name__ == '__main__':
|
||||
logger.info(f"[Flask 初始化] {dir_desc}不存在,创建:{dir_path}")
|
||||
os.makedirs(dir_path, exist_ok=True)
|
||||
|
||||
# 启动提示(含访问示例)
|
||||
# 启动提示
|
||||
logger.info("\n[Flask 服务启动成功!] 支持的接口:")
|
||||
logger.info(f"1. 模型下载 → http://服务器IP:5000/model/download/resource/models/xxx.pt")
|
||||
logger.info(f"2. 人脸图片 → http://服务器IP:5000/up_images/xxx.jpg")
|
||||
logger.info(f"3. 检测图片 → http://服务器IP:5000/resource/dect/xxx.jpg 或 http://服务器IP:5000/images/xxx.jpg\n")
|
||||
|
||||
# 启动服务(禁用 debug 和自动重载,避免多线程冲突)
|
||||
# 启动服务(禁用 debug 和自动重载)
|
||||
app.run(
|
||||
host="0.0.0.0", # 允许外部IP访问
|
||||
port=5000, # 与 main.py 中 Flask 端口一致
|
||||
host="0.0.0.0",
|
||||
port=5000,
|
||||
debug=False,
|
||||
use_reloader=False
|
||||
)
|
||||
@ -11,6 +11,7 @@ from mysql.connector import Error as MySQLError
|
||||
|
||||
# 复用项目依赖
|
||||
from ds.db import db
|
||||
from encryption.encrypt_decorator import encrypt_response
|
||||
from schema.model_schema import (
|
||||
ModelCreateRequest,
|
||||
ModelUpdateRequest,
|
||||
@ -190,6 +191,7 @@ def get_current_conf_threshold():
|
||||
|
||||
# 1. 上传模型(保持不变)
|
||||
@router.post("", response_model=APIResponse, summary="上传YOLO模型(.pt格式)")
|
||||
@encrypt_response()
|
||||
async def upload_model(
|
||||
name: str = Form(..., description="模型名称"),
|
||||
description: str = Form(None, description="模型描述"),
|
||||
@ -281,6 +283,7 @@ async def upload_model(
|
||||
|
||||
# 2. 获取模型列表(保持不变)
|
||||
@router.get("", response_model=APIResponse, summary="获取模型列表(分页)")
|
||||
@encrypt_response()
|
||||
async def get_model_list(
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(10, ge=1, le=100),
|
||||
@ -337,6 +340,7 @@ async def get_model_list(
|
||||
|
||||
# 3. 获取默认模型(保持不变)
|
||||
@router.get("/default", response_model=APIResponse, summary="获取当前默认模型")
|
||||
@encrypt_response()
|
||||
async def get_default_model():
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -379,6 +383,7 @@ async def get_default_model():
|
||||
|
||||
# 4. 获取单个模型详情(保持不变)
|
||||
@router.get("/{model_id}", response_model=APIResponse, summary="获取单个模型详情")
|
||||
@encrypt_response()
|
||||
async def get_model(model_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -414,6 +419,7 @@ async def get_model(model_id: int):
|
||||
|
||||
# 5. 更新模型信息(保持不变)
|
||||
@router.put("/{model_id}", response_model=APIResponse, summary="更新模型信息")
|
||||
@encrypt_response()
|
||||
async def update_model(model_id: int, model_update: ModelUpdateRequest):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -497,6 +503,7 @@ async def update_model(model_id: int, model_update: ModelUpdateRequest):
|
||||
|
||||
# 5.1 更换默认模型(添加置信度参数)
|
||||
@router.put("/{model_id}/set-default", response_model=APIResponse, summary="更换默认模型(自动重启服务)")
|
||||
@encrypt_response()
|
||||
async def set_default_model(
|
||||
model_id: int,
|
||||
conf_threshold: float = Query(0.8, ge=0.01, le=0.99, description="模型检测置信度阈值(0.01-0.99)")
|
||||
@ -591,6 +598,7 @@ async def set_default_model(
|
||||
|
||||
# 6. 删除模型(保持不变)
|
||||
@router.delete("/{model_id}", response_model=APIResponse, summary="删除模型")
|
||||
@encrypt_response()
|
||||
async def delete_model(model_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
@ -650,6 +658,7 @@ async def delete_model(model_id: int):
|
||||
|
||||
# 7. 下载模型文件(保持不变)
|
||||
@router.get("/{model_id}/download", summary="下载模型文件")
|
||||
@encrypt_response()
|
||||
async def download_model(model_id: int):
|
||||
conn = None
|
||||
cursor = None
|
||||
|
||||
@ -25,6 +25,7 @@ router = APIRouter(
|
||||
# 1. 创建敏感信息记录
|
||||
# ------------------------------
|
||||
@router.post("", response_model=APIResponse, summary="创建敏感信息记录")
|
||||
@encrypt_response()
|
||||
async def create_sensitive(
|
||||
sensitive: SensitiveCreateRequest,
|
||||
current_user: UserResponse = Depends(get_current_user) # 补充登录认证依赖(与其他接口保持一致)
|
||||
@ -76,7 +77,9 @@ async def create_sensitive(
|
||||
# ------------------------------
|
||||
# 2. 获取单个敏感信息记录
|
||||
# ------------------------------
|
||||
|
||||
@router.get("/{sensitive_id}", response_model=APIResponse, summary="获取单个敏感信息记录")
|
||||
@encrypt_response()
|
||||
async def get_sensitive(
|
||||
sensitive_id: int,
|
||||
current_user: UserResponse = Depends(get_current_user) # 需登录认证
|
||||
@ -125,8 +128,7 @@ async def get_sensitive(
|
||||
async def get_sensitive_list(
|
||||
page: int = Query(1, ge=1, description="页码(默认1,最小1)"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="每页条数(默认10,1-100)"),
|
||||
name: Optional[str] = Query(None, description="敏感词关键词搜索(模糊匹配)"),
|
||||
current_user: UserResponse = Depends(get_current_user) # 需登录认证
|
||||
name: Optional[str] = Query(None, description="敏感词关键词搜索(模糊匹配)")
|
||||
):
|
||||
"""
|
||||
获取敏感信息分页列表:
|
||||
@ -191,6 +193,7 @@ async def get_sensitive_list(
|
||||
# 4. 更新敏感信息记录
|
||||
# ------------------------------
|
||||
@router.put("/{sensitive_id}", response_model=APIResponse, summary="更新敏感信息记录")
|
||||
@encrypt_response()
|
||||
async def update_sensitive(
|
||||
sensitive_id: int,
|
||||
sensitive_update: SensitiveUpdateRequest,
|
||||
@ -269,6 +272,7 @@ async def update_sensitive(
|
||||
# 5. 删除敏感信息记录
|
||||
# ------------------------------
|
||||
@router.delete("/{sensitive_id}", response_model=APIResponse, summary="删除敏感信息记录")
|
||||
@encrypt_response()
|
||||
async def delete_sensitive(
|
||||
sensitive_id: int,
|
||||
current_user: UserResponse = Depends(get_current_user) # 需登录认证
|
||||
|
||||
@ -27,6 +27,7 @@ router = APIRouter(
|
||||
# 1. 用户注册接口
|
||||
# ------------------------------
|
||||
@router.post("/register", response_model=APIResponse, summary="用户注册")
|
||||
@encrypt_response()
|
||||
async def user_register(request: UserRegisterRequest):
|
||||
"""
|
||||
用户注册:
|
||||
@ -78,6 +79,7 @@ async def user_register(request: UserRegisterRequest):
|
||||
# 2. 用户登录接口
|
||||
# ------------------------------
|
||||
@router.post("/login", response_model=APIResponse, summary="用户登录(获取 Token)")
|
||||
@encrypt_response()
|
||||
async def user_login(request: UserLoginRequest):
|
||||
"""
|
||||
用户登录:
|
||||
@ -140,6 +142,7 @@ async def user_login(request: UserLoginRequest):
|
||||
# 3. 获取当前登录用户信息(需认证)
|
||||
# ------------------------------
|
||||
@router.get("/me", response_model=APIResponse, summary="获取当前用户信息")
|
||||
@encrypt_response()
|
||||
async def get_current_user_info(
|
||||
current_user: UserResponse = Depends(get_current_user) # 依赖认证中间件
|
||||
):
|
||||
@ -159,6 +162,7 @@ async def get_current_user_info(
|
||||
# 4. 获取用户列表(仅需登录权限)
|
||||
# ------------------------------
|
||||
@router.get("/list", response_model=APIResponse, summary="获取用户列表")
|
||||
@encrypt_response()
|
||||
async def get_user_list(
|
||||
page: int = Query(1, ge=1, description="页码,从1开始"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="每页条数,1-100之间"),
|
||||
|
||||
Reference in New Issue
Block a user