Files
FastapiAdmin/backend/app/utils/hash_bcrpy_util.py
T
zhangtao c2ca6d19ac refactor: 优化代码注释和文档字符串格式
style: 统一代码风格和格式

docs: 完善函数和方法的文档字符串

refactor(base_model): 移除冗余的表名和表参数生成方法

refactor(constant): 更新返回码注释格式

refactor(router_class): 添加路由处理器的详细文档

refactor(database): 完善数据库连接函数的文档

refactor(security): 添加认证类和方法的详细文档

refactor(validator): 更新验证器函数的文档格式

refactor(serialize): 优化序列化工具类的文档

refactor(response): 完善响应类的文档字符串

refactor(dependencies): 添加依赖函数的详细文档

refactor(initialize): 完善初始化脚本的文档

refactor(plugin): 添加生命周期和中间件注册的文档

refactor(service): 完善服务层方法的文档

refactor(controller): 添加控制器方法的详细文档

refactor(crud): 完善CRUD操作的文档字符串

refactor(schema): 简化模型类并移除冗余字段

refactor(param): 更新查询参数类的注释格式

refactor(template): 优化代码生成模板的格式

refactor(console): 添加控制台输出功能的实现

refactor(util): 完善工具函数的文档字符串
2025-10-18 16:31:28 +08:00

211 lines
5.9 KiB
Python

# -*- coding: utf-8 -*-
import hashlib
import os
from typing import Optional, Any
from passlib.context import CryptContext
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from itsdangerous import URLSafeSerializer
from app.core.logger import logger
# 密码加密配置
PwdContext = CryptContext(
schemes=["bcrypt"],
deprecated="auto",
bcrypt__rounds=12 # 设置加密轮数,增加安全性
)
class PwdUtil:
"""
密码工具类,提供密码加密和验证功能
"""
@classmethod
def verify_password(cls, plain_password: str, password_hash: str) -> bool:
"""
校验密码是否匹配
参数:
- plain_password (str): 明文密码。
- password_hash (str): 加密后的密码哈希值。
返回:
- bool: 密码是否匹配。
"""
return PwdContext.verify(plain_password, password_hash)
@classmethod
def set_password_hash(cls, password: str) -> str:
"""
对密码进行加密
参数:
- password (str): 明文密码。
返回:
- str: 加密后的密码哈希值。
"""
return PwdContext.hash(password)
@classmethod
def check_password_strength(cls, password: str) -> Optional[str]:
"""
检查密码强度
参数:
- password (str): 明文密码。
返回:
- Optional[str]: 如果密码强度不够返回提示信息,否则返回None。
"""
if len(password) < 6:
return "密码长度至少6位"
if not any(c.isupper() for c in password):
return "密码需要包含大写字母"
if not any(c.islower() for c in password):
return "密码需要包含小写字母"
if not any(c.isdigit() for c in password):
return "密码需要包含数字"
return None
class AESCipher:
"""AES 加密器"""
def __init__(self, key: bytes | str) -> None:
"""
初始化 AES 加密器。
参数:
- key (bytes | str): 密钥,16/24/32 bytes 或 16 进制字符串。
返回:
- None
"""
self.key = key if isinstance(key, bytes) else bytes.fromhex(key)
def encrypt(self, plaintext: bytes | str) -> bytes:
"""
AES 加密。
参数:
- plaintext (bytes | str): 加密前的明文。
返回:
- bytes: 加密后的密文(前16字节为随机IV)。
"""
if not isinstance(plaintext, bytes):
plaintext = str(plaintext).encode('utf-8')
iv = os.urandom(16)
cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()
padder = padding.PKCS7(cipher.algorithm.block_size).padder() # type: ignore
padded_plaintext = padder.update(plaintext) + padder.finalize()
ciphertext = encryptor.update(padded_plaintext) + encryptor.finalize()
return iv + ciphertext
def decrypt(self, ciphertext: bytes | str) -> str:
"""
AES 解密。
参数:
- ciphertext (bytes | str): 解密前的密文,bytes 或 16 进制字符串。
返回:
- str: 解密后的明文。
"""
ciphertext = ciphertext if isinstance(ciphertext, bytes) else bytes.fromhex(ciphertext)
iv = ciphertext[:16]
ciphertext = ciphertext[16:]
cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv), backend=backend)
decryptor = cipher.decryptor()
unpadder = padding.PKCS7(cipher.algorithm.block_size).unpadder() # type: ignore
padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()
plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
return plaintext.decode('utf-8')
class Md5Cipher:
"""MD5 加密器"""
@staticmethod
def encrypt(plaintext: bytes | str) -> str:
"""
MD5 加密。
参数:
- plaintext (bytes | str): 加密前的明文。
返回:
- str: MD5 十六进制摘要。
"""
md5 = hashlib.md5()
if not isinstance(plaintext, bytes):
plaintext = str(plaintext).encode('utf-8')
md5.update(plaintext)
return md5.hexdigest()
class ItsDCipher:
"""ItsDangerous 加密器"""
def __init__(self, key: bytes | str) -> None:
"""
初始化 ItsDangerous 加密器。
参数:
- key (bytes | str): 密钥,16/24/32 bytes 或 16 进制字符串。
返回:
- None
"""
self.key = key if isinstance(key, bytes) else bytes.fromhex(key)
def encrypt(self, plaintext: Any) -> str:
"""
ItsDangerous 加密。
参数:
- plaintext (Any): 加密前的明文。
返回:
- str: 加密后的密文(URL安全)。
异常:
- Exception: 加密失败时使用 MD5 作为降级,错误已记录。
"""
serializer = URLSafeSerializer(self.key)
try:
ciphertext = serializer.dumps(plaintext)
except Exception as e:
logger.error(f'ItsDangerous encrypt failed: {e}')
ciphertext = Md5Cipher.encrypt(plaintext)
return ciphertext
def decrypt(self, ciphertext: str) -> Any:
"""
ItsDangerous 解密。
参数:
- ciphertext (str): 解密前的密文。
返回:
- Any: 解密后的明文;失败时返回原密文。
异常:
- Exception: 解密失败时记录错误并返回原密文。
"""
serializer = URLSafeSerializer(self.key)
try:
plaintext = serializer.loads(ciphertext)
except Exception as e:
logger.error(f'ItsDangerous decrypt failed: {e}')
plaintext = ciphertext
return plaintext