fix(api): auth 用 bcrypt 直调替代 passlib(修复容器 __about__ 缺失致登录失败)

- 替换 passlib.context.CryptContext 为直接 bcrypt 调用
- hash_password: bcrypt.hashpw + gensalt
- verify_password: bcrypt.checkpw + 异常处理
- 保持公共接口不变(hash_password/verify_password/create_token/verify_token)
- 移除 passlib 导入,直接使用 bcrypt 模块
- 现有 $2b$12$... bcrypt hash 仍可验证通过

修复问题:
- passlib 1.7.4 探测 bcrypt.__about__.__version__ 导致 AttributeError
- 现代 bcrypt 移除了 __about__ 属性
- 致使容器内密码验证失败,登录跳过

验证结果:
- 本地 test_auth.py: 3/3 PASS
- 容器 test_auth.py: 3/3 PASS
- 容器 smoke JWT LOGIN: PASS(之前 SKIP)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-06 19:55:06 +08:00
parent effd3caa4a
commit 4723554e29
2 changed files with 44 additions and 43 deletions
+6 -4
View File
@@ -3,11 +3,10 @@
import os
from datetime import datetime, timedelta, timezone
import jwt
from passlib.context import CryptContext
import bcrypt
from fastapi import HTTPException, status
_CONFIG = {"secret": "change-me", "expire_minutes": 60, "algorithm": "HS256"}
_pwd = CryptContext(schemes=["bcrypt"], deprecated="auto")
def set_jwt_config(secret: str, expire_minutes: int, algorithm: str = "HS256"):
@@ -15,11 +14,14 @@ def set_jwt_config(secret: str, expire_minutes: int, algorithm: str = "HS256"):
def hash_password(password: str) -> str:
return _pwd.hash(password)
return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")
def verify_password(password: str, password_hash: str) -> bool:
return _pwd.verify(password, password_hash)
try:
return bcrypt.checkpw(password.encode("utf-8"), password_hash.encode("utf-8"))
except (ValueError, TypeError):
return False
def create_token(username: str) -> str: