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

使用Rust openidconnect crate自定义Claims遇trait绑定错误求助

问题

在使用openidconnect crate对接Zitadel实例时,基础认证流程正常,但需要从Zitadel获取额外Claims。现有openidconnect::CoreClient定义如下:

pub type CoreClient = Client<
    EmptyAdditionalClaims,
    CoreAuthDisplay,
    CoreGenderClaim,
    CoreJweContentEncryptionAlgorithm,
    CoreJwsSigningAlgorithm,
    CoreJsonWebKeyType,
    CoreJsonWebKeyUse,
    CoreJsonWebKey,
    CoreAuthPrompt,
    StandardErrorResponse<CoreErrorResponseType>,
    CoreTokenResponse,
    CoreTokenType,
    CoreTokenIntrospectionResponse,
    CoreRevocableToken,
    CoreRevocationErrorResponse,
>;

尝试将其中的EmptyAdditionalClaims替换为自定义的MyClaims:

#[derive(Serialize, Deserialize, Debug)]
pub struct MyClaims {
    // 自定义额外Claims字段,比如zitadel的用户属性
}

impl AdditionalClaims for MyClaims {}

然后复制CoreClient定义并替换第一个参数创建MyClient:

pub type MyClient = Client<
    MyClaims,
    // 复制上述其他参数
    // ...
>;

最终出现以下编译错误:

error[E0277]: the trait bound `StandardTokenResponse<IdTokenFields<EmptyAdditionalClaims, EmptyExtraTokenFields, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType>, BasicTokenType>: openidconnect::TokenResponse<MyClaims, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, BasicTokenType>` is not satisfied
   --> app/src/auth.rs:92:17
    |
92  |     pub client: MyClient,
    |                 ^^^^^^^^ the trait `openidconnect::TokenResponse<MyClaims, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType, BasicTokenType>` is not implemented for `StandardTokenResponse<IdTokenFields<EmptyAdditionalClaims, EmptyExtraTokenFields, CoreGenderClaim, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreJsonWebKeyType>, BasicTokenType>`
    |
    = help: the trait `openidconnect::TokenResponse<AC, GC, JE, JS, JT, TT>` is implemented for `StandardTokenResponse<IdTokenFields<AC, EF, GC, JE, JS, JT>, TT>`
note: required by a bound in `openidconnect::Client`
   --> /home/domma/development/axum-zitadell-demo/openidconnect-rs/src/lib.rs:794:9
    |
794 |     TR: TokenResponse<AC, GC, JE, JS, JT, TT>,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Client`

解决方案

错误核心是CoreTokenResponse本质是StandardTokenResponse<IdTokenFields<EmptyAdditionalClaims, ...>, ...>,它的泛型参数仍使用EmptyAdditionalClaims,和自定义的MyClaims不匹配。需要同时替换TokenResponse中的IdTokenFields泛型参数,而非仅替换Client的第一个参数。

完整实现示例

1. 定义自定义Claims

use serde::{Deserialize, Serialize};
use openidconnect::AdditionalClaims;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MyClaims {
    // 匹配Zitadel返回的实际额外字段,示例为常见字段
    pub username: String,
    pub email_verified: bool,
    pub name: String,
    pub preferred_username: String,
}

impl AdditionalClaims for MyClaims {}

2. 定义自定义IdTokenFields和TokenResponse

use openidconnect::{
    CoreGenderClaim, CoreJweContentEncryptionAlgorithm,
    CoreJwsSigningAlgorithm, CoreJsonWebKeyType, BasicTokenType,
    IdTokenFields, StandardTokenResponse, EmptyExtraTokenFields
};

// 替换IdTokenFields中的额外Claims类型为MyClaims
pub type MyIdTokenFields = IdTokenFields<
    MyClaims,
    EmptyExtraTokenFields,
    CoreGenderClaim,
    CoreJweContentEncryptionAlgorithm,
    CoreJwsSigningAlgorithm,
    CoreJsonWebKeyType,
>;

// 基于自定义IdTokenFields创建TokenResponse
pub type MyTokenResponse = StandardTokenResponse<MyIdTokenFields, BasicTokenType>;

3. 定义自定义Client类型

use openidconnect::Client;

pub type MyClient = Client<
    MyClaims,
    openidconnect::CoreAuthDisplay,
    CoreGenderClaim,
    CoreJweContentEncryptionAlgorithm,
    CoreJwsSigningAlgorithm,
    CoreJsonWebKeyType,
    openidconnect::CoreJsonWebKeyUse,
    openidconnect::CoreJsonWebKey,
    openidconnect::CoreAuthPrompt,
    openidconnect::StandardErrorResponse<openidconnect::CoreErrorResponseType>,
    MyTokenResponse, // 此处使用自定义的TokenResponse
    openidconnect::CoreTokenType,
    openidconnect::CoreTokenIntrospectionResponse,
    openidconnect::CoreRevocableToken,
    openidconnect::CoreRevocationErrorResponse,
>;

4. 使用自定义Client获取额外Claims

use openidconnect::{AuthorizationCode, ClientId, ClientSecret, RedirectUrl, Scope, IssuerUrl};

async fn create_my_client() -> Result<MyClient, openidconnect::Error<openidconnect::StandardErrorResponse<openidconnect::CoreErrorResponseType>>> {
    let issuer = IssuerUrl::new("https://your-zitadel-instance.com".to_string())?;
    let client_id = ClientId::new("your-client-id".to_string());
    let client_secret = ClientSecret::new("your-client-secret".to_string());
    let redirect_url = RedirectUrl::new("http://localhost:3000/callback".to_string())?;

    MyClient::discover(issuer)
        .await?
        .set_client_id(client_id)
        .set_client_secret(client_secret)
        .set_redirect_uri(redirect_url)
        .build()
}

async fn handle_callback(code: AuthorizationCode, client: MyClient) -> Result<(), openidconnect::Error<openidconnect::StandardErrorResponse<openidconnect::CoreErrorResponseType>>> {
    let token_response = client.exchange_code(code).await?;
    
    // 提取自定义Claims
    let id_token = token_response.id_token().ok_or(openidconnect::Error::MissingIdToken)?;
    let my_claims = id_token.additional_claims();
    
    println!("用户名: {}", my_claims.username);
    println!("邮箱验证状态: {}", my_claims.email_verified);
    
    Ok(())
}

关键说明

  • Client的泛型参数中,第11个参数TR(TokenResponse)必须与第一个参数AC(AdditionalClaims)匹配,即TokenResponse内部的IdTokenFields必须使用相同的AC类型。
  • MyClaims的字段名和类型需与Zitadel实际返回的额外Claims完全一致,可在Zitadel控制台的用户属性或应用配置中确认。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:35:37