You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastAPI中解密Django使用Fernet加密存储的数据库字段数据

根因定位

问题核心是FastAPI侧字段映射不匹配 + 解密逻辑和Django侧未对齐:

  1. Django自定义EncryptedField通过返回BinaryField作为内部类型,读写时Django ORM会自动完成数据库二进制值和Python bytes类型的转换,你在from_db_value拿到的是已经转换后的标准加密bytes。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:09:02