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

如何通过Duende Identity Server令牌端点返回外部提供商令牌给客户端

在Duende Identity Server中返回外部身份提供商的令牌到Custom属性

核心实现思路

要将Google的API令牌加入Duende令牌端点响应的Custom属性,需要分两步操作:

  1. 捕获外部登录过程中获取的Google访问令牌
  2. 通过Duende的扩展点自定义令牌响应,将令牌注入Custom字段

步骤1:配置Google认证并捕获令牌

首先在Google认证配置中,确保保存外部令牌并将其暴露为可访问的数据源:

方式A:通过AuthenticationProperties保存令牌

builder.Services.AddAuthentication()
    .AddGoogle(options =>
    {
        options.ClientId = "你的Google客户端ID";
        options.ClientSecret = "你的Google客户端密钥";
        // 开启令牌保存,将Google令牌存入AuthenticationProperties
        options.SaveTokens = true;
        // 添加需要调用的Google API权限范围
        options.Scope.Add("https://www.googleapis.com/auth/drive.readonly");
    });

方式B:将令牌添加到用户Claims中

如果希望令牌随用户身份主体一起传递,可以在Google登录的OnCreatingTicket事件中添加自定义Claim:

builder.Services.AddAuthentication()
    .AddGoogle(options =>
    {
        options.ClientId = "你的Google客户端ID";
        options.ClientSecret = "你的Google客户端密钥";
        options.Scope.Add("https://www.googleapis.com/auth/drive.readonly");
        
        options.Events.OnCreatingTicket = context =>
        {
            // 将Google访问令牌添加到用户身份Claims
            context.Identity.AddClaim(new Claim("google_access_token", context.AccessToken));
            return Task.CompletedTask;
        };
    });

步骤2:自定义令牌响应生成器

实现Duende提供的ICustomTokenResponseGenerator接口,在令牌响应生成时将Google令牌注入Custom属性:

public class CustomTokenResponseGenerator : ICustomTokenResponseGenerator
{
    private readonly ITokenResponseGenerator _innerGenerator;
    // 如果用方式A需要依赖IHttpContextAccessor,方式B则不需要
    private readonly IHttpContextAccessor? _httpContextAccessor;

    // 构造函数:方式B可移除IHttpContextAccessor参数
    public CustomTokenResponseGenerator(ITokenResponseGenerator innerGenerator, IHttpContextAccessor? httpContextAccessor = null)
    {
        _innerGenerator = innerGenerator;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task<TokenResponse> GenerateAsync(TokenResponseGenerationContext context)
    {
        // 先执行默认的令牌响应生成逻辑
        var response = await _innerGenerator.GenerateAsync(context);

        // 仅针对授权码流程的令牌请求处理(可根据实际需求调整)
        if (context.Request.GrantType == OidcConstants.GrantTypes.AuthorizationCode)
        {
            string? googleAccessToken = null;

            // 方式A:从AuthenticationProperties中提取令牌
            if (_httpContextAccessor != null)
            {
                var externalAuthResult = await _httpContextAccessor.HttpContext
                    .AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
                if (externalAuthResult.Succeeded)
                {
                    googleAccessToken = externalAuthResult.Properties.GetTokenValue("access_token");
                }
            }

            // 方式B:从用户主体Claims中提取令牌(优先级高于方式A)
            if (string.IsNullOrEmpty(googleAccessToken))
            {
                googleAccessToken = context.Subject.FindFirstValue("google_access_token");
            }

            // 将令牌加入Custom属性
            if (!string.IsNullOrEmpty(googleAccessToken))
            {
                response.Custom ??= new Dictionary<string, object>();
                response.Custom["google_access_token"] = googleAccessToken;
            }
        }

        return response;
    }
}

步骤3:注册自定义生成器

将自定义的令牌响应生成器注册到Duende的依赖注入容器中,替换默认实现:

builder.Services.AddIdentityServer()
    // 其他配置(如AddInMemoryClients、AddInMemoryIdentityResources等)
    .AddCustomTokenResponseGenerator<CustomTokenResponseGenerator>();

注意事项

  • 确保IdentityServerConstants.ExternalCookieAuthenticationScheme的Cookie在令牌请求阶段仍有效(授权码流程中,code交换token时该Cookie通常会保留)
  • 若使用方式B,需确保google_access_token Claim不会被Duende默认的Claims过滤规则移除,可在AddIdentityServer配置中调整Claims映射或保留规则
  • 根据实际业务场景,可扩展支持其他外部身份提供商的令牌注入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:05:18