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

如何在Rust结构体中定义动态类型字段适配JWT的amr声明?

解决JWT中amr声明的动态类型解码问题

方案一:用serde_with快速搞定(新手首选)

serde_with这个库专门解决serde的序列化/反序列化痛点,其中的OneOrMany工具能自动处理“单个值或数组”的场景,不用自己写复杂逻辑。

  1. 先在Cargo.toml里添加依赖:
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
jsonwebtoken = "9.0"
serde_with = "3.0"
  1. 定义Claims结构体时,给amr字段添加serde属性:
use serde::Deserialize;
use serde_with::rust::one_or_many;

#[derive(Debug, Deserialize)]
struct Claims {
    // 其他字段(如sub、exp等)按需添加
    #[serde(with = "one_or_many")]
    amr: Vec<String>,
}

不管amr是单个字符串(比如"pwd")还是字符串数组(比如["pwd", "mfa"]),都会被解析成Vec<String>——单个字符串会自动转成仅含一个元素的数组,完美适配两种格式。

方案二:手动实现枚举反序列化(理解原理用)

如果不想引入额外依赖,可以自己定义枚举并实现Deserialize trait来处理两种情况:

  1. 定义覆盖两种场景的Amr枚举:
use serde::de::{self, Visitor, Deserializer};
use serde::Deserialize;
use std::fmt;

#[derive(Debug, Clone)]
enum Amr {
    Single(String),
    Multiple(Vec<String>),
}

// 为Amr实现Deserialize trait
impl<'de> Deserialize<'de> for Amr {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // 自定义Visitor处理两种类型
        struct AmrVisitor;

        impl<'de> Visitor<'de> for AmrVisitor {
            type Value = Amr;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("单个字符串或字符串数组")
            }

            // 处理单个字符串的情况
            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
            where
                E: de::Error,
            {
                Ok(Amr::Single(value.to_string()))
            }

            // 处理字符串数组的情况
            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: de::SeqAccess<'de>,
            {
                let mut vec = Vec::new();
                while let Some(s) = seq.next_element()? {
                    vec.push(s);
                }
                Ok(Amr::Multiple(vec))
            }
        }

        deserializer.deserialize_any(AmrVisitor)
    }
}
  1. 在Claims结构体中使用该枚举:
#[derive(Debug, Deserialize)]
struct Claims {
    // 其他字段...
    amr: Amr,
}

解码时两种格式的amr都能正确解析,之后可以通过match判断是单个值还是数组来做后续处理。

你之前枚举报错的原因

你之前用自定义枚举出现Err(Error("expected value", ...)),大概率是反序列化逻辑有问题——比如只处理了数组没处理字符串,或者没有用deserialize_any兼容两种类型,导致serde无法识别输入格式。上面的手动实现已经覆盖了两种场景,直接使用即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 23:35:04