59 lines
1.6 KiB
Python
59 lines
1.6 KiB
Python
"""密码哈希与 Token 工具。
|
||
|
||
密码:Argon2id(argon2-cffi)
|
||
Token:secrets.token_urlsafe + SHA-256 hash + Fernet 加密
|
||
"""
|
||
|
||
import hashlib
|
||
import secrets
|
||
|
||
from argon2 import PasswordHasher
|
||
from argon2.exceptions import VerifyMismatchError
|
||
from cryptography.fernet import Fernet
|
||
|
||
from app.core.config import get_settings
|
||
|
||
_ph = PasswordHasher()
|
||
|
||
|
||
def hash_password(password: str) -> str:
|
||
"""Argon2id 哈希密码。"""
|
||
return _ph.hash(password)
|
||
|
||
|
||
def verify_password(password: str, password_hash: str) -> bool:
|
||
"""验证密码。"""
|
||
try:
|
||
return _ph.verify(password_hash, password)
|
||
except VerifyMismatchError:
|
||
return False
|
||
|
||
|
||
def generate_token() -> str:
|
||
"""生成 128bit 熵 URL-safe token(22 字符)。"""
|
||
return secrets.token_urlsafe(16)
|
||
|
||
|
||
def hash_token(token: str) -> str:
|
||
"""SHA-256 哈希 token(用于数据库存储和查询)。"""
|
||
return hashlib.sha256(token.encode()).hexdigest()
|
||
|
||
|
||
def get_fernet() -> Fernet:
|
||
"""从 SECRET_KEY 派生 Fernet 实例(用于加密存储 token 原文)。"""
|
||
settings = get_settings()
|
||
# 将 SECRET_KEY 转为 32 字节 Fernet key(简单派生,MVP 够用)
|
||
key = hashlib.sha256(settings.secret_key.encode()).digest()
|
||
import base64
|
||
|
||
return Fernet(base64.urlsafe_b64encode(key))
|
||
|
||
|
||
def encrypt_token(token: str) -> str:
|
||
"""Fernet 加密 token 原文。"""
|
||
return get_fernet().encrypt(token.encode()).decode()
|
||
|
||
|
||
def decrypt_token(encrypted: str) -> str:
|
||
"""Fernet 解密 token 原文。"""
|
||
return get_fernet().decrypt(encrypted.encode()).decode() |