Azure Identity:自定义令牌验证以验证多租户应用程序中的颁发者

Posted

技术标签:

【中文标题】Azure Identity:自定义令牌验证以验证多租户应用程序中的颁发者【英文标题】:Azure Identity: Custom token validation to validate issuers in a multi tenant app 【发布时间】:2021-06-04 22:17:59 【问题描述】:

我按照Microsofts article 实现了我自己的颁发者验证(“自定义令牌验证”是该部分的标题)。

这似乎适用于在 app-only 上下文中发布的 JWT-Token,但是当我的 API 的第一次调用是通过 用户委托 发布的 JWT 令牌时失败了.

我发现是这行代码导致了问题:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApi(Configuration);
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>

  var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
  options.Events.OnTokenValidated = async context =>
  
       await existingOnTokenValidatedHandler(context);
      // Your code to add extra configuration that will be executed after the current event implementation.
      options.TokenValidationParameters.ValidIssuers = new[]  /* list of valid issuers */ ;
      options.TokenValidationParameters.ValidAudiences = new[]  /* list of valid audiences */;
  
);

这是我上面发布的链接的原始代码。 我通过以下方式实现了自己的颁发者验证:

        services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
                        
            var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
            options.TokenValidtionParameters.RoleClaimType = "roles";
            options.Events.OnTokenValidated = async context =>
            
                await existingOnTokenValidatedHandler(context);
                options.Authority = "https://login.microsoftonline.com/common";
                var validTenants = FileTenantStore.Tenants.Select(x => x.AzureAdTenantId).ToList();
                options.TokenValidationParameters.ValidIssuers = GetValidIssuers(validTenants);
                options.TokenValidationParameters.IssuerValidator = ValidateIssuers;
            ;
        );

我有一个多租户应用,所以我只需要让一些租户通过和拒绝最多。

这个解决方案的行为有点奇怪:

始终使用 App-Only 令牌调用 API。 使用 Delegated 令牌调用 API 失败并显示以下错误消息,甚至不会跳转到回调:

无法验证令牌。 Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDW10303:发行人: 'https://login.microsoftonline.com/OUR_TENANT_ID/v2.0', 与为此应用程序提供的任何有效发行人不匹配。 在 Microsoft.Identity.Web.Resource.AadIssuerValidator.Validate(字符串 实际Issuer、SecurityToken securityToken、TokenValidationParameters 验证参数) 在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateIssuer(字符串 发行者,JwtSecurityToken jwtToken,TokenValidationParameters 验证参数) 在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters 验证参数) 在 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(字符串 令牌、TokenValidationParameters 验证参数、SecurityToken& 验证令牌) 在 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()

所以在这种情况下,从不调用“OnTokenValidated”。

第一次使用 App-Only 令牌调用 API,然后使用委托令牌调用 API 可以正常工作。

我可以通过将“OnTokenValidated”-Callback 中的行移到上一级来解决这个问题:

        services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
                        
            var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;

            options.TokenValidationParameters.RoleClaimType = "roles";
            var validTenants = FileTenantStore.Tenants.Select(x => x.AzureAdTenantId).ToList();
            options.TokenValidationParameters.ValidIssuers = GetValidIssuers(validTenants);
            options.TokenValidationParameters.IssuerValidator = ValidateIssuers;
            options.Events.OnTokenValidated = async context =>
                              
                await existingOnTokenValidatedHandler(context);
                options.Authority = "https://login.microsoftonline.com/common";

            ;
        );

我现在什至可以删除回调“OnTokenValidated”,但这感觉不对,因为 Microsoft 文章给出了明确的说明。 我可以这样做,还是我的解决方案是一个安全问题?

【问题讨论】:

GetValidIssuers(validTenants)返回了什么?根据错误消息'https://login.microsoftonline.com/OUR_TENANT_ID/v2.0',与GetValidIssuers(validTenants) 返回的任何有效颁发者都不匹配。我猜它返回 v1.0 版本格式:'https://sts.windows.net/TENANT_ID'. 你是对的。它返回一个地址为“login.microsoftonline.comTenant_id/v2.0”和“sts.windows.netTENANT_ID”的数组。两者都有。 你能拿一个 JWT 令牌并在jwt.ms 中解码以查看颁发者是什么(iss 声明)? docs.microsoft.com/azure/active-directory/develop/… 你误会了。我 100% 确定令牌没问题。在使用应用程序令牌后,委托令牌也可以正常工作。问题是:为什么第一次使用用户委托的 JWT 调用我的 API 时 OnTokenValidated 没有执行(是正确的,我已经这样做了) 【参考方案1】:

如果您在 netcore>3 中,您可以使用 AddMicrosoftIdentityWebApiAuthentication 扩展方法。将 subscribeToOpenIdConnectMiddlewareDiagnosticsEvents 设置为 true 并启用调试日志记录以查看终止特定令牌检查的事件。

根据您的代码:

services.AddMicrosoftIdentityWebApiAuthentication(Configuration,
    jwtBearerScheme: JwtBearerDefaults.AuthenticationScheme,
    subscribeToJwtBearerMiddlewareDiagnosticsEvents: true);

【讨论】:

请您详细说明“启用调试日志记录以查看终止检查您的特定令牌的事件”。对不起我的无知,但如果你的意思是调试控制台,那么不会报告任何事件。谢谢。 查看Web API Troubleshooting 和Logging 部分以在开发过程中启用更多跟踪

以上是关于Azure Identity:自定义令牌验证以验证多租户应用程序中的颁发者的主要内容,如果未能解决你的问题,请参考以下文章

Api 的自定义身份验证 Azure 移动服务

令牌服务器上自定义端点的 Identity Server 4 客户端凭据

实现 JWT 身份验证 Azure Function 3.x - 使用 JWT 令牌获取当前用户的声明

如何使用 Python 在 Azure AD 中验证令牌

在 Blazor 中同时使用 ASP.Net Core Identity 和 Azure 身份验证

如何使用自定义策略模式实现 jwt 令牌基础身份验证以在 .net 核心中进行授权?