Files
TJWaterServerBinary/app/core/encryption.py

93 lines
2.4 KiB
Python

from cryptography.fernet import Fernet
from typing import Optional
import base64
import os
from app.core.config import settings
class Encryptor:
"""
使用 Fernet (对称加密) 实现数据加密/解密
适用于加密敏感配置、用户数据等
"""
def __init__(self, key: Optional[bytes] = None):
"""
初始化加密器
Args:
key: 加密密钥,如果为 None 则从环境变量读取
"""
if key is None:
key_str = os.getenv("ENCRYPTION_KEY") or settings.ENCRYPTION_KEY
if not key_str:
raise ValueError(
"ENCRYPTION_KEY not found in environment variables or .env. "
"Generate one using: Encryptor.generate_key()"
)
key = key_str.encode()
self.fernet = Fernet(key)
def encrypt(self, data: str) -> str:
"""
加密字符串
Args:
data: 待加密的明文字符串
Returns:
Base64 编码的加密字符串
"""
if not data:
return data
encrypted_bytes = self.fernet.encrypt(data.encode())
return encrypted_bytes.decode()
def decrypt(self, data: str) -> str:
"""
解密字符串
Args:
data: Base64 编码的加密字符串
Returns:
解密后的明文字符串
"""
if not data:
return data
decrypted_bytes = self.fernet.decrypt(data.encode())
return decrypted_bytes.decode()
@staticmethod
def generate_key() -> str:
"""
生成新的 Fernet 加密密钥
Returns:
Base64 编码的密钥字符串
"""
key = Fernet.generate_key()
return key.decode()
# 全局加密器实例(懒加载)
_encryptor: Optional[Encryptor] = None
def is_encryption_configured() -> bool:
return bool(os.getenv("ENCRYPTION_KEY") or settings.ENCRYPTION_KEY)
def get_encryptor() -> Encryptor:
"""获取全局加密器实例"""
global _encryptor
if _encryptor is None:
_encryptor = Encryptor()
return _encryptor
# 向后兼容(延迟加载)
def __getattr__(name):
if name == "encryptor":
return get_encryptor()
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")