简体   繁体   English

ASP.NET Core 2.0 AzureAD身份验证无法正常工作

[英]ASP.NET Core 2.0 AzureAD Authentication not working

I have an ASP.NET Core 2.0 application setup that I want to use AzureAd for the authentication with my company's directory. 我有一个ASP.NET Core 2.0应用程序设置,我想使用AzureAd进行我公司目录的身份验证。 I have setup the classes and startup method and have the authentication piece working, the problem that I'm having is that I'm trying to setup and event handler to the OnAuthorizationCodeReceived event, so that I can request a user token that will then be used for Microsoft graph calls. 我已经设置了类和启动方法并使身份验证工作正常,我遇到的问题是我正在尝试设置OnAuthorizationCodeReceived事件的事件处理程序,以便我可以请求一个用户令牌用于Microsoft图形调用。

In my Startup.cs I have the following code 在我的Startup.cs中,我有以下代码

public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddAzureAd(options => Configuration.Bind("AzureAd", options))
            .AddCookie();

            services.AddMvc();

            services.AddSingleton(Configuration);
            services.AddSingleton<IGraphAuthProvider, GraphAuthProvider>();
            services.AddTransient<IGraphSDKHelper, GraphSDKHelper>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

Then in the AzureAdAuthenticationBuilderExtensions.cs I have the following code. 然后在AzureAdAuthenticationBuilderExtensions.cs中,我有以下代码。

public static class AzureAdAuthenticationBuilderExtensions
{        
    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, IConfiguration configuration)
        => builder.AddAzureAd(_ => { }, configuration);

    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions, 
        IConfiguration configuration)
    {
        builder.Services.Configure(configureOptions);
        builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
        builder.AddOpenIdConnect(opts =>
        {
            opts.ResponseType = "code id_token";

            opts.ClientId = configuration["AzureAd:ClientId"];
            opts.Authority = $"{configuration["AzureAd:Instance"]}{configuration["AzureAd:TenantId"]}";
            opts.UseTokenLifetime = true;
            opts.CallbackPath = configuration["AzureAd:CallbackPath"];
            opts.ClientSecret = configuration["AzureAd:ClientSecret"];
            opts.RequireHttpsMetadata = false;

            opts.Events = new OpenIdConnectEvents
            {
                OnAuthorizationCodeReceived = async context =>
                {
                    var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);

                    var distributedCache = context.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
                    var userId = context.Principal
                        .FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
                        .Value;
                    var cache = new AdalDistributedTokenCache(distributedCache, userId);
                    var authContext = new AuthenticationContext(context.Options.Authority, cache);
                    await authContext.AcquireTokenByAuthorizationCodeAsync(context.TokenEndpointRequest.Code,
                        new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute), credential, context.Options.Resource);
                    context.HandleCodeRedemption();
                }
            };
        });
        return builder;
    }

    private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
    {
        private readonly AzureAdOptions _azureOptions;

        public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
        {
            if (azureOptions != null)
            {
                _azureOptions = azureOptions.Value;
            }
        }

        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;
            options.ClientSecret = _azureOptions.ClientSecret;
        }

        public void Configure(OpenIdConnectOptions options)
        {
            Configure(Options.DefaultName, options);
        }
    }
}

Then AddAzureAd method is being called and I can see it walk through all of the code in this method, but when I put a breakpoint in the OnAuthorizationCodeReceived method that breakpoint never gets hit. 然后调用AddAzureAd方法,我可以看到它遍历此方法中的所有代码,但是当我在OnAuthorizationCodeReceived方法中放置一个断点时,断点永远不会被命中。 I've done a bunch of reading and it looks like what I have is right, so I'm guessing that I must be missing something simple here, but can't find the problem. 我已经完成了一堆阅读,它看起来就像我拥有的​​是正确的,所以我猜我必须在这里找不到简单的东西,但找不到问题。

Editted I'm now hitting the OnAuthorizationCodeReceived event, but now the application is failing to continue to log in getting the following error 编辑我现在正在点击OnAuthorizationCodeReceived事件,但现在应用程序无法继续登录获取以下错误

SecurityTokenException: Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''."
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+<HandleRequestAsync>d__12.MoveNext()

Stack Query Cookies Headers
SecurityTokenException: Unable to validate the 'id_token', no suitable ISecurityTokenValidator was found for: ''."
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler+<HandleRequestAsync>d__12.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()

The OpenIdConnect component for Asp.net core 2.0 uses implicit flow(the value of response_type is id_token ). Asp.net core 2.0的OpenIdConnect组件使用隐式流( response_type值为id_token )。

To fire the OnAuthorizationCodeReceived the event, we should use the hybrid flow which's 'response_type' parameter contains code value.(eg. id_token code ). 要触发OnAuthorizationCodeReceived事件,我们应该使用混合流,其'response_type'参数包含code值。(例如id_token code )。 And we need set it through the OpenIdConnectOptions like code below: 我们需要通过OpenIdConnectOptions设置它,如下面的代码:

.AddOpenIdConnect(options =>
{
    options.Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]);
    options.ClientId = Configuration["AzureAd:ClientId"];
    options.ResponseType = "code id_token";     
});

options.Events = new OpenIdConnectEvents
{
    OnAuthorizationCodeReceived = async context =>
    {
        var credential = new ClientCredential(context.Options.ClientId, context.Options.ClientSecret);

        var authContext = new AuthenticationContext(context.Options.Authority);
        var authResult=await authContext.AcquireTokenByAuthorizationCodeAsync(context.TokenEndpointRequest.Code,
            new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute), credential, context.Options.Resource);
        context.HandleCodeRedemption(authResult.AccessToken, context.ProtocolMessage.IdToken);
    },
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM