From 3ea8eff34d8d0fb722cf47aac5127d142e02c51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=BF=97=E5=BC=BA?= <1452366827@qq.com> Date: Sat, 5 Sep 2026 07:48:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=9B=BF=E6=8D=A2=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E5=93=88=E5=B8=8C=E5=AE=9E=E7=8E=B0=E4=B8=BA=E5=8E=9F?= =?UTF-8?q?=E7=94=9Fbcrypt=E5=B9=B6=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构CryptUtils类,替换原有的passlib密码哈希逻辑为直接使用bcrypt库;添加密码字节长度限制以符合bcrypt原生72字节上限;更新pyproject.toml配置,新增bcrypt依赖并将passlib设为可选依赖;统一代码缩进格式 --- app/utils/CrpyUtils.py | 69 ++++++++++++++++++++++++------------------ pyproject.toml | 3 +- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/app/utils/CrpyUtils.py b/app/utils/CrpyUtils.py index 80de57e..e3f3af0 100644 --- a/app/utils/CrpyUtils.py +++ b/app/utils/CrpyUtils.py @@ -1,48 +1,57 @@ from datetime import timedelta, datetime, timezone from typing import TypedDict, Literal, TypeAlias +import bcrypt import jwt -from passlib.context import CryptContext from app.config.env import env -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +BCRYPT_MAX_BYTES = 72 -# token的类型,access用于接口认证,refresh用于刷新access token,verify用于激活用户账号 AccessTokenType: TypeAlias = Literal["access", "refresh", "verify", "api"] class TokenInfo(TypedDict): - # 用户名信息 - username: str - # token过期时间 - exp: datetime - type: AccessTokenType + username: str + exp: datetime + type: AccessTokenType + + +def _safe_password_bytes(password: str) -> bytes: + data = password.encode("utf-8") + if len(data) > BCRYPT_MAX_BYTES: + data = data[:BCRYPT_MAX_BYTES] + return data class CryptUtils: - @staticmethod - def get_password_hash(password: str): - return pwd_context.hash(password) + @staticmethod + def get_password_hash(password: str): + return bcrypt.hashpw(_safe_password_bytes(password), bcrypt.gensalt()).decode( + "utf-8" + ) - @staticmethod - def verify_password(plain_password: str, hashed_password: str): - return pwd_context.verify(plain_password, hashed_password) + @staticmethod + def verify_password(plain_password: str, hashed_password: str): + try: + return bcrypt.checkpw( + _safe_password_bytes(plain_password), hashed_password.encode("utf-8") + ) + except ValueError: + return False + except Exception: + return False - @staticmethod - def create_token( - username: str, - type: AccessTokenType, - expires_delta: timedelta - ): - data: TokenInfo = { - "username": username, - "type": type, - "exp": datetime.now(timezone.utc) + expires_delta - } - return jwt.encode(data, env.jwt_secret_key, env.jwt_algorithm) + @staticmethod + def create_token(username: str, type: AccessTokenType, expires_delta: timedelta): + data: TokenInfo = { + "username": username, + "type": type, + "exp": datetime.now(timezone.utc) + expires_delta, + } + return jwt.encode(data, env.jwt_secret_key, env.jwt_algorithm) - @staticmethod - def get_token_info(token: str) -> TokenInfo: - data = jwt.decode(token, env.jwt_secret_key, algorithms=[env.jwt_algorithm]) - return data + @staticmethod + def get_token_info(token: str) -> TokenInfo: + data = jwt.decode(token, env.jwt_secret_key, algorithms=[env.jwt_algorithm]) + return data diff --git a/pyproject.toml b/pyproject.toml index 5aff946..0620c94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,8 @@ psutil = "^7.0.0" asyncmy = "^0.2.10" sqlmodel = "^0.0.24" greenlet = "^3.2.3" -passlib = {extras = ["bcrypt"], version = "^1.7.4"} +passlib = {extras = ["bcrypt"], version = "^1.7.4", optional = true} +bcrypt = "^4.0.0" pyjwt = "^2.10.1" python-multipart = "^0.0.20" langgraph = "^0.6.3"