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

将JWT字符串反序列化为嵌套Pydantic模型时遇验证错误求助

问题:JWT字符串反序列化为嵌套Pydantic模型失败

尝试将JWT字符串直接反序列化为嵌套Pydantic模型,使用@model_validator(mode="before")在验证前解码JWT并合并payload,但调用model_validate时抛出ValidationError,提示无法将字符串传入嵌套模型。

代码示例

from typing import Dict, Any
import jwt
from pydantic import BaseModel, model_validator


class JwtDecodeError(Exception):
    """自定义JWT解码异常"""
    pass


class JwtBaseModel(BaseModel):
    session_jwt: str

    @classmethod
    @model_validator(mode="before")
    def decode_jwt(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        """无需签名验证解码JWT"""
        token = values.get("session_jwt")
        if not token:
            raise ValueError("必须提供JWT token")

        try:
            decoded_payload = jwt.decode(token, options={"verify_signature": False})
        except jwt.DecodeError as e:
            raise JwtDecodeError(f"JWT解码失败: {str(e)}")

        values.update(decoded_payload)
        return values


class UsernameSignature(JwtBaseModel):
    valid: bool
    busy: bool
    exp: int
    payment_required: bool


class Username(BaseModel):
    busy: bool
    meta: dict
    payment_required: bool
    signature: UsernameSignature
    valid: bool
    username: str


model_json = {
    "busy": False,
    "meta": {
        "gameSessionId": "",
        "tracing": None
    },
    "payment_required": True,
    "signature": "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6ImpkamRvd2RiIiwidmFsaWQiOnRydWUsImJ1c3kiOmZhbHNlLCJleHAiOjE3MjY3NzY1OTksInBheW1lbnRfcmVxdWlyZWQiOnRydWV9.VjCpW2rY8MEgcVKJrx9Igz05-OnPdJuZxmg4wFUuy25Ixik02O9BkqXoOrfdgo0QR_-BPzB1AdAoMoveu3eqVHwtKGOXzG__eU6kObOlcowqB7iu9SwfK6TXmh1djaxhCCOveOIcj3UOlXQIZ4b6JuFSkezzHAUfaBe2KZskhyFH107MPxLnwWnVL3jOJwOcM7ierd96Y1xyDqmBlL9k8hotTWHwsNlTi0H2GjXWdMk8c54eMGIBhma66q_S__LQ9k1VSZkIj1awOpPzBrUdxMNw9B6J1bsPN8ajLIrLM_oHrXWGDGpIK9Clmbi6XfPe87X09pKutRapKU5nCqOWog",
    "username": "jdjdowdb",
    "valid": True
}

parsed_model = Username.model_validate(model_json)

错误信息

pydantic_core._pydantic_core.ValidationError: 1 validation error for Username
signature
  Input should be a valid dictionary or instance of UsernameSignature [type=model_type, input_value='eyJhbGciOiJSUzI1NiJ9.eyJ...e87X09pKutRapKU5nCqOWog', input_type=str]

解决方案

问题根源

当前JwtBaseModel的decode_jwt验证器仅处理包含session_jwt键的字典输入,但嵌套字段signature传入的是纯JWT字符串,而非字典,导致验证器未触发,Pydantic直接尝试将字符串转换为UsernameSignature实例,引发错误。

方法一:修改JwtBaseModel支持直接处理字符串输入

调整验证器,使其能识别字符串输入并直接解码:

class JwtBaseModel(BaseModel):
    @classmethod
    @model_validator(mode="before")
    def decode_jwt(cls, values: Any) -> Dict[str, Any]:
        """支持直接解码字符串JWT或含session_jwt的字典"""
        if isinstance(values, str):
            token = values
        else:
            token = values.get("session_jwt")
            if not token:
                raise ValueError("必须提供JWT token")

        try:
            decoded_payload = jwt.decode(token, options={"verify_signature": False})
        except jwt.DecodeError as e:
            raise JwtDecodeError(f"JWT解码失败: {str(e)}")

        return decoded_payload

# 移除JwtBaseModel中的session_jwt字段,现在直接处理字符串输入
class UsernameSignature(JwtBaseModel):
    valid: bool
    busy: bool
    exp: int
    payment_required: bool

方法二:在父模型中用字段验证器处理signature字段

无需修改JwtBaseModel,直接在Username模型中添加字段验证器解码JWT:

from pydantic import field_validator

class Username(BaseModel):
    busy: bool
    meta: dict
    payment_required: bool
    signature: UsernameSignature
    valid: bool
    username: str

    @field_validator("signature", mode="before")
    def decode_signature(cls, v: str) -> UsernameSignature:
        try:
            decoded_payload = jwt.decode(v, options={"verify_signature": False})
            return UsernameSignature(**decoded_payload)
        except jwt.DecodeError as e:
            raise JwtDecodeError(f"签名JWT解码失败: {str(e)}")

两种方法都能实现将JWT字符串解码后填充到嵌套模型字段中,可根据实际场景选择:方法一更通用,适合所有继承JwtBaseModel的类直接处理JWT字符串;方法二更灵活,针对特定字段定制解码逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 04:47:07