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

在ASP.NET Core中将Azure AD ID令牌兑换为自签名访问令牌

Azure AD认证场景:自定义自签名访问令牌的生成与Cookie存储时机

你当前通过Azure AD完成身份验证并获取到ID令牌及用户信息,但在OnUserInformationReceived事件中生成自定义令牌的时机并不合适。以下是正确的实现方案:

最佳时机:使用OnTokenValidated事件

OnTokenValidated是OpenIdConnect认证流程中ID令牌验证通过后触发的事件,此时用户身份已被确认,是生成并存储自定义令牌的最优节点。

实现步骤与代码示例

修改OpenIdConnect的事件配置,替换原有的OnUserInformationReceived逻辑:

authenticationBuilder.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    // 保留原有配置
    options.Authority = $"https://login.microsoftonline.com/{oidcTenantId}/v2.0/";
    options.ClientId = oidcClientId;
    options.ClientSecret = oidcClientSecret;
    options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
    options.CallbackPath = "/signin-oidc";
    options.TokenValidationParameters.IssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcInstance).Validate;
    options.GetClaimsFromUserInfoEndpoint = true;

    // 替换为OnTokenValidated事件处理逻辑
    options.Events.OnTokenValidated = async context =>
    {
        // 从已验证的身份主体中提取preferred_username声明
        var userIdClaim = context.Principal.Claims.FirstOrDefault(c => c.Type == "preferred_username");
        if (userIdClaim == null)
        {
            throw new InvalidOperationException("Azure AD返回的ID令牌中缺少必需的preferred_username声明");
        }

        // 生成自定义自签名访问令牌(将preferred_username映射为sub声明)
        int lifetimeInMinutes = 5;
        string jwt = MyTokenRules.GenerateJwt(
            userId: userIdClaim.Value, // 此处将preferred_username映射为访问令牌的sub声明
            issuer: jwtSettings.Issuer,
            audience: jwtSettings.Audience,
            key: Environment.GetEnvironmentVariable(jwtSettings.SecretKeyName) ?? string.Empty,
            duration: TimeSpan.FromMinutes(lifetimeInMinutes));

        // 方式1:将自定义令牌作为Claim存入身份Cookie,随用户身份一同存储
        var identity = context.Principal.Identity as ClaimsIdentity;
        identity?.AddClaim(new Claim("custom_access_token", jwt));

        // 方式2:用独立Cookie存储自定义令牌(适合需要单独管控令牌生命周期的场景)
        context.Response.Cookies.Append(
            "CustomAccessToken",
            jwt,
            new CookieOptions
            {
                HttpOnly = true, // 防范XSS攻击
                Secure = true,   // 仅HTTPS环境传输
                SameSite = SameSiteMode.Lax,
                Expires = DateTimeOffset.UtcNow.AddMinutes(lifetimeInMinutes)
            });

        await Task.CompletedTask;
    };
});

为什么不推荐OnUserInformationReceived?

该事件触发于用户信息端点返回数据后,但此时认证流程尚未完成,身份主体(Principal)还未被Cookie认证中间件序列化存储。在此处生成的令牌无法确保被正确持久化到Cookie中,时序上存在风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:57:08