From 6c8da0ee2f1fff5d68c8bef4c51766499bed45e2 Mon Sep 17 00:00:00 2001 From: smallbailangui Date: Sun, 30 Nov 2025 15:56:43 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=A8=A1=E6=8B=9F=E5=8D=A0=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/app/api/v1/endpoints/project.py | 2 +- src/backend/app/service/project_service.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/backend/app/api/v1/endpoints/project.py b/src/backend/app/api/v1/endpoints/project.py index 6781ba5..a4ed0f4 100644 --- a/src/backend/app/api/v1/endpoints/project.py +++ b/src/backend/app/api/v1/endpoints/project.py @@ -56,7 +56,7 @@ async def update_project_info( current_user: Any = Depends(deps.get_current_active_user), ) -> Any: try: - return await project_service.update_project_info_service(db, project_id, current_user.user_id, data.model_dump(exclude_unset=True)) + return await project_service.update_project_info_service(db, project_id, current_user.user_id, update_data.model_dump(exclude_unset=True)) except ItemNotFoundException: raise HTTPException(status_code=404, detail="Not found") diff --git a/src/backend/app/service/project_service.py b/src/backend/app/service/project_service.py index d4d07b8..c4eafdf 100644 --- a/src/backend/app/service/project_service.py +++ b/src/backend/app/service/project_service.py @@ -40,10 +40,15 @@ async def create_project_service( # 1. 创建关联的 DatabaseInstance (占位) # 必须先创建它,否则 Project 的 instance_id 外键会报错 + # 使用合法的占位数据 (非空字符串,非0端口) new_instance = await crud_database_instance.create( db, db_type=db_type, - db_host="", db_port=0, db_name="pending", db_username="", db_password="", + db_host="127.0.0.1", # TODO:后续改成真实的ip地址,修改:使用本地回环地址占位 + db_port=3306, # 修改:使用标准端口占位 + db_name="pending_init", # TODO:修改:更有意义的占位名 + db_username="pending_user", # TODO:修改:非空用户名 + db_password="pending_password", # TODO:修改:非空密码 status="inactive" ) -- 2.34.1 From de337b18eb43f14da0b98064bc79586baefad72b Mon Sep 17 00:00:00 2001 From: smallbailangui Date: Sun, 30 Nov 2025 15:59:55 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E4=B8=AD=E7=9A=84token=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/app/service/project_service.py | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/backend/app/service/project_service.py b/src/backend/app/service/project_service.py index c4eafdf..7849ece 100644 --- a/src/backend/app/service/project_service.py +++ b/src/backend/app/service/project_service.py @@ -3,6 +3,7 @@ from typing import Optional, Dict, Any from sqlalchemy.ext.asyncio import AsyncSession as Session from datetime import datetime, timedelta, timezone +from jose import jwt, JWTError # 新增 # 隐式绝对导入 from crud.crud_project import crud_project @@ -21,11 +22,27 @@ from core.config import config # --- 辅助函数 --- async def _verify_delete_token(token: str, user_id: int, project_id: int) -> bool: try: - payload = decode_jwt_token(token) - if payload.get("sub") != str(user_id) or payload.get("project_id") != project_id: + # 直接使用 jwt.decode 获取完整 payload,而不是用 auth.decode_jwt_token + payload = jwt.decode( + token, + config.jwt.secret_key, + algorithms=[config.jwt.algorithm] + ) + + token_sub = payload.get("sub") + token_pid = payload.get("project_id") + + # 1. 验证是否属于当前用户 + if str(token_sub) != str(user_id): return False + + # 2. 验证是否针对当前项目 + if token_pid is None or int(token_pid) != int(project_id): + return False + return True - except Exception: + except (JWTError, ValueError, TypeError, AttributeError): + # 任何解码错误或类型转换错误都视为验证失败 return False -- 2.34.1 From 83d10a4534391df9ce6f244df6e7fe86b95c0698 Mon Sep 17 00:00:00 2001 From: smallbailangui Date: Sun, 30 Nov 2025 16:16:38 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dredis=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E7=94=A8=E6=88=B7=E7=99=BB=E5=87=BA=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/app/core/auth.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/backend/app/core/auth.py b/src/backend/app/core/auth.py index 20c1e09..4dacbbc 100644 --- a/src/backend/app/core/auth.py +++ b/src/backend/app/core/auth.py @@ -11,6 +11,8 @@ from pydantic import BaseModel from core.config import config from core.exceptions import TokenInvalidException from core.log import log +# 导入 Redis 获取函数 +from redis.redis import get_redis # 密码哈希上下文 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") @@ -81,12 +83,27 @@ def create_access_token(data: dict) -> str: # 5. 获取当前活跃用户 ID (依赖注入用) async def get_current_active_user( - token: str = Depends(oauth2_scheme) + token: str = Depends(oauth2_scheme) ) -> int: """ 负责解析 Token,检查是否过期/无效,返回 user_id。 注意:此函数不查数据库,只解密 Token。查库逻辑请在 deps.py 中基于此 user_id 进行。 """ + # 检查 Token 是否在 Redis 白名单中 + redis = get_redis() + if redis: + # 这里的 key 格式必须与 user_service.service_save_token_in_redis 保持一致 + token_key = f"token:{token}" + is_valid = await redis.get(token_key) + + if not is_valid: + log.warning(f"Token invalid (logged out or expired in redis): {token[:10]}...") + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Token has been revoked (logged out)", + headers={"WWW-Authenticate": "Bearer"}, + ) + try: user_id = decode_jwt_token(token) return user_id -- 2.34.1