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

如何用Pydantic赋值时转明文密码为bytes哈希并适配Beanie验证?

使用Pydantic自动哈希明文密码为bytes类型的问题

我希望通过Pydantic在赋值阶段,自动将明文字符串密码通过哈希函数转换为bytes类型的哈希值,但当前代码无法正常运行,最简示例如下:

import bcrypt
from pydantic import BaseModel, field_validator

def hash_password(password: str) -> bytes:
    return bcrypt.hashpw(password.encode('utf-8'), salt = bcrypt.gensalt())

class Password(BaseModel):
    hash_value: bytes
    
    @field_validator("hash_value")
    @classmethod
    def set_password(cls, plain_password: str) -> bytes:
        return hash_password(plain_password)
    
class Settings:
    DEFAULT_PASSWORD = "my_plain_password"
    
settings = Settings()
    
password_doc = Password(
    hash_value = settings.DEFAULT_PASSWORD
)

最初我错误地将hash_value声明为str类型,没注意到bcrypt.hashpw返回的是bytes类型,虽然能调用hash_password函数,但隐式类型转换会导致哈希密码失效。

现在的问题是:Pydantic期望hash_value是bytes类型,会先把字符串settings.DEFAULT_PASSWORD隐式转为bytes,再传入期望接收字符串的set_password方法,最终抛出错误:

Traceback (most recent call last):
  File "xxx", line 20, in <module>
    password_doc = Password(
                   ^^^^^^^^^
  File "xxx", line 176, in __init__
    self.__pydantic_validator__.validate_python(data, self_instance=self)
  File "xxx", line 13, in set_password
    return hash_password(plain_password)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "xxx", line 5, in hash_password
    return bcrypt.hashpw(password.encode('utf-8'), salt = bcrypt.gensalt())
                         ^^^^^^^^^^^^^^^
AttributeError: 'bytes' object has no attribute 'encode'. Did you mean: 'decode'?

补充问题(编辑1)

感谢解答后大部分问题已解决,但发现set_password方法的调用次数超出预期。我使用Beanie Model存储关联Password文档的Config文档:

class Password(base.Password, Document):
    hash_value: bytes
    
    @field_validator("hash_value", mode="before")
    @classmethod
    def set_password(cls, plain_password: str | bytes) -> bytes:
        # 新的实现逻辑

class Config(base.Config, Document):
    password: Link[Password]
    
    def get_password(self) -> Link[Password]:
        return self.password

当执行models.Config.find_one(fetch_links=True)读取Config文档并获取关联链接时,set_password方法会被调用,此时传入的是存储的二进制哈希值,因此我需要在参数为二进制时直接返回该值。请问这是预期行为还是代码存在bug?


进一步说明(编辑2)

从数据库读取哈希密码时的二次验证应该是Beanie自动执行的,这很合理,因为数据库可能被外部修改。我原本不想让set_password方法接收二进制参数,但使用mode="before"后隐式转换不再发生,因此为了数据库验证需要允许参数为bytes类型。

内容的提问来源于stack exchange,提问作者DevilsThumb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:05:55