如何在FastAPI中解密Django使用Fernet加密存储的数据库字段数据
根因定位
问题核心是FastAPI侧字段映射不匹配 + 解密逻辑和Django侧未对齐:
- Django自定义
EncryptedField通过返回BinaryField作为内部类型,读写时Django ORM会自动完成数据库二进制值和Python bytes类型的转换,你在from_db_value拿到的是已经转换后的标准加密bytes。 - FastAPI侧拿到的
pbkdf2_sha256开头的值是Django默认的密码哈希格式,说明要么是模型字段映射错误,误读了password字段,要么是SQLModel把二进制字段自动转成了字符串格式,没有拿到原始加密bytes。
解决方案
步骤1:修正FastAPI侧User模型字段定义
确保encrypted_field字段类型和数据库实际存储类型完全匹配,不要定义为字符串类型:
from sqlmodel import Field, SQLModel # 如果使用PostgreSQL,引入BYTEA类型做适配 from sqlalchemy.dialects.postgresql import BYTEA class User(SQLModel, table=True): # 其他字段省略 # 通用数据库写法 encrypted_field: bytes = Field(default=None) # PostgreSQL专用写法,避免驱动自动转成hex字符串 # encrypted_field: bytes = Field(sa_type=BYTEA, default=None)
步骤2:对齐解密逻辑
解密逻辑要和Django侧的force_bytes处理逻辑对齐,避免不同类型输入导致解密失败,不想引入Django依赖可以自行实现简易版的类型转换:
from cryptography.fernet import Fernet # 替代Django的force_bytes,确保输入统一转成标准bytes def to_bytes(value, encoding="utf-8"): if isinstance(value, bytes): return value if isinstance(value, memoryview): return value.tobytes() return str(value).encode(encoding) def decrypt(value: bytes): fernet = Fernet(FERNET_KEY) raw_encrypted = to_bytes(value) decrypted_bytes = fernet.decrypt(raw_encrypted) return decrypted_bytes.decode("utf-8")
步骤3:核验字段值
修改模型定义后打印读取到的encrypted_field值,确认值开头为gAAAAA(标准Fernet加密结果的固定开头),再调用解密方法即可得到正确明文。
内容的提问来源于stack exchange,提问作者Murilo Sitonio
相关产品推荐
相关产品推荐

