Azure AD 多租户,.Net Core Web API 与 JWT 令牌

Posted

技术标签:

【中文标题】Azure AD 多租户,.Net Core Web API 与 JWT 令牌【英文标题】:Azure AD Multi Tenant ,.Net Core Web API with JWT Token 【发布时间】:2020-06-28 10:52:39 【问题描述】:

所以我提出了这个问题Azure AD Multi Tenant ,.Net Core Web API with MSAL(Microsoft Authentication Libary),它向我展示了如何打开错误输出。

为什么我现在要用我的令牌得到这个,我猜是 aud 权利和 iss 多租户广告令牌?

AuthenticationFailed: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: 'YMELHT0gvb0mxoSDoYfomjqfjYU', InternalId: '2c34a300-21bb-4eb1-b3b9-1944f1be7470'. , KeyId: YMELHT0gvb0mxoSDoYfomjqfjYU
'. 
kid: 'YMELHT0gvb0mxoSDoYfomjqfjYU'. 
Exceptions caught:
 ''.
token: '

    "alg": "RS256",
    "typ": "JWT",
    "nonce": "bWqlNum32nkLGFA4s5lE83AEZ6hRUzqi4r4-3JMZLdw",
    "x5t": "YMELHT0gvb0mxoSDoYfomjqfjYU",
    "kid": "YMELHT0gvb0mxoSDoYfomjqfjYU"

.
    "aud": "00000003-0000-0000-c000-000000000000",
    "iss": "https://sts.windows.net/abc60396-1ed0-4fa3-a3d0-597adf1366a5/",
    "iat": 1584438416,
    "nbf": 1584438416,
    "exp": 1584442316,
    "acct": 0,
    "acr": "1",
    "aio": "42NgYNh7TvzDvOILBsl/7E+U+vxP6y5rmJERnny04o5ZM2vJjmwA",
    "amr": ["pwd"],
    "app_displayname": "AzureAdTest",
    "appid": "A134d6c8-8078-2924-9e90-98cef862eb9a",
    "appidacr": "0",
    "family_name": "Bob",
    "given_name": "Bob",
    "ipaddr": "111.111.124.18",
    "name": "Bob Powell",
    "oid": "5b2dfaea-41fb-4a76-93da-6b4c04041f4d",
    "platf": "3",
    "puid": "10032000A35A0EE1",
    "scp": "openid profile User.Read email",
    "sub": "NM4nVqUfyC-6pF66I1Wef8Bvl7rhnpB_UBv7fX-qMHU",
    "tid": "abc60396-1ed0-4fa3-a3d0-597adf1366a5",
    "unique_name": "a@b.onmicrosoft.com",
    "upn": "a@b.onmicrosoft.com",
    "uti": "-mwXtFoS1kGJjorQqzI0AA",
    "ver": "1.0",
    "xms_st": 
        "sub": "p7nf6_rRkoqINUHy3cl_qRQ2F-DaCfFwQgy6gTQv_QY"
    ,
    "xms_tcdt": 1583932579

'.

我之前的问题是:

我相信我有 Microsoft 身份验证库 (MSAL) javascript 拉回 JWT 令牌,使用具有以下配置的 azure AD 多租户。 基于此链接https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant。我相信我只需要以下两个值。

clientId: "A134d6c8-8078-2924-9e90-98cef862eb9a" // this would be the app registrations client id(application)
authority: "https://login.microsoftonline.com/common"

然后我如何配置一个 .net core 3 web api,它可以处理这个 JWT 令牌并通过我传递 Authorization: Bearer 标头来验证 [Authorize] 端点。

我目前在响应中收到此错误,这不是很有帮助!

AuthenticationFailed: IDX10511: Signature validation failed. Keys tried: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. 
kid: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. 
Exceptions caught:
 '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.

Startup.cs代码如下

using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;

namespace MultiTenantApi

    public class Startup
    
        public Startup(IConfiguration configuration)
        

            Configuration = configuration;
        

        public IConfiguration Configuration  get; 

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        
            services.AddCors(x =>
            
                x.AddDefaultPolicy(cfg =>
                
                    cfg.AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                );
            );

            services.AddAuthentication(cfg =>
                
                    cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                )
                .AddJwtBearer(opt =>
                
                    opt.Authority = "https://login.microsoftonline.com/common";
                    opt.Audience = "api://A134d6c8-8078-2924-9e90-98cef862eb9a"; // Set this to the App ID URL for the web API, which you created when you registered the web API with Azure AD.
                    opt.TokenValidationParameters = new TokenValidationParameters
                    
                        ValidateIssuer = false
                    ;
                    opt.Events = new JwtBearerEvents()
                    
                        OnAuthenticationFailed = AuthenticationFailed
                    ;
                );

            services.AddControllers();

        

        private Task AuthenticationFailed(AuthenticationFailedContext arg)
        
            // For debugging purposes only!
            var s = $"AuthenticationFailed: arg.Exception.Message";
            arg.Response.ContentLength = s.Length;
            arg.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(s), 0, s.Length);
            return Task.FromResult(0);
        
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        
            if (env.IsDevelopment())
            
                app.UseDeveloperExceptionPage();
            

            app.UseHttpsRedirection();

            app.UseStaticFiles(); // Added

            app.UseRouting();
            app.UseCors(); //Added

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            
                endpoints.MapControllers();
            );

        

    

【问题讨论】:

使用 OnAuthenticationFailed 可以挽救生命,谢谢,直接引导我解决问题。 【参考方案1】:

在上面 juunas 响应的帮助下,我将范围从 user.read 更改为以下这是我的客户端 ID(应用程序 ID),后跟 .default

var tokenRequest = 
    scopes: ["A134d6c8-8078-2924-9e90-98cef862eb9a/.default"]
;
await this.app.acquireTokenSilent(tokenRequest)
   ... etc

在这之后我可以看到 aud 值不再是图形 api 一个

"aud": "A134d6c8-8078-2924-9e90-98cef862eb9"

在 C# API 中,我的代码现在可以在 ConfigureServices Startup.cs 文件中使用它

services.AddAuthentication(cfg =>

    cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddJwtBearer(opt =>

    opt.Authority = "https://login.microsoftonline.com/common";
    opt.Audience = "api://A134d6c8-8078-2924-9e90-98cef862eb9a"; // Set this to the App ID URL for the web API, which you created when you registered the web API with Azure AD.

    opt.TokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuer = true, 
        ValidateAudience = true, 
        ValidAudiences = new List<String>
        
            // you could add a list of valid audiences
            "A134d6c8-8078-2924-9e90-98cef862eb9a"
        , 
        ValidIssuers = new List<string>
        
            // Add tenant id after https://sts.windows.net/
            "https://sts.windows.net/YourTenantId"
        
    ;
    opt.Events = new JwtBearerEvents()
    
        OnAuthenticationFailed = AuthenticationFailed
    ;
);

【讨论】:

【参考方案2】:

您似乎正在尝试验证用于 MS Graph API 的令牌。 这些令牌是特殊的,您不应尝试验证它们。 您应该始终只接受用于您的 API 的令牌,而不是其他 API。

我知道是这样的原因是因为:

"aud": "00000003-0000-0000-c000-000000000000"

这就是 Microsoft Graph API 的受众价值。

对于用于您的 API 并供您验证的令牌, 这应该是您 API 的客户端 ID 或应用 ID URI。

当您在前端获取访问令牌时, 使用范围your-api-client-id/.default 获取静态分配的权限, 或一组动态范围,如['your-api-client-id/scope-a', 'your-api-client-id/scope-b']。 这些范围是在您的应用注册时定义的。

【讨论】:

谢谢你的工作,虽然不是很明白这一切,但它确实有效!用代码添加答案以显示我是如何工作的,干杯 使用 Auth url 扩展资源参数 (?resource=[ClientId])... 比如https://login.microsoftonline.com/[TenantId]/oauth2/authorize?resource=[ClientId] @jkyree OP 正在使用 MSAL,它使用 v2.0 端点。它使用scope 参数,而不是resource 参数。

以上是关于Azure AD 多租户,.Net Core Web API 与 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

Azure AD B2C 租户和普通 Azure AD 租户有啥区别?

如何在 .NET Core Web 应用程序的单个实例中使用动态租户对 Azure Active Directory 中的用户进行身份验证?

如何将 Azure AD 和非 Azure AD 令牌添加到同一个 .NET Core Api

Azure AD 与 ASP.NET Core MVC 中的标识

Azure AD 限制整个 ASP.NET Core API

Azure AD 在 .NET Core 3.1 中未进行身份验证