問(wèn)題描述
我有一個(gè) ASP.NET Core 2.0 應(yīng)用程序設(shè)置,我想使用 AzureAd 對(duì)我公司的目錄進(jìn)行身份驗(yàn)證.我已經(jīng)設(shè)置了類和啟動(dòng)方法并使身份驗(yàn)證工作正常,我遇到的問(wèn)題是我正在嘗試為 OnAuthorizationCodeReceived 事件設(shè)置事件處理程序,以便我可以請(qǐng)求一個(gè)用戶令牌,然后用于 Microsoft 圖形調(diào)用.
I have an ASP.NET Core 2.0 application setup that I want to use AzureAd for the authentication with my company's directory. 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.
在我的 Startup.cs 中,我有以下代碼
In my Startup.cs I have the following code
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?}");
});
}
然后在 AzureAdAuthenticationBuilderExtensions.cs 我有以下代碼.
Then in the AzureAdAuthenticationBuilderExtensions.cs I have the following code.
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);
}
}
}
然后調(diào)用 AddAzureAd 方法,我可以看到它遍歷該方法中的所有代碼,但是當(dāng)我在 OnAuthorizationCodeReceived 方法中放置斷點(diǎn)時(shí),斷點(diǎn)永遠(yuǎn)不會(huì)被命中.我做了一堆閱讀,看起來(lái)我所擁有的是正確的,所以我猜我一定在這里遺漏了一些簡(jiǎn)單的東西,但找不到問(wèn)題.
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. 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.
已編輯我現(xiàn)在正在點(diǎn)擊 OnAuthorizationCodeReceived 事件,但現(xiàn)在應(yīng)用程序無(wú)法繼續(xù)登錄,出現(xiàn)以下錯(cuò)誤
Editted I'm now hitting the OnAuthorizationCodeReceived event, but now the application is failing to continue to log in getting the following error
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()
推薦答案
Asp.net core 2.0的OpenIdConnect組件使用隱式流(response_type
的值為id_token
).
The OpenIdConnect component for Asp.net core 2.0 uses implicit flow(the value of response_type
is id_token
).
要觸發(fā) OnAuthorizationCodeReceived
事件,我們應(yīng)該使用 'response_type' 參數(shù)包含 code
值的混合流.(例如.id_token 代碼
).我們需要通過(guò) OpenIdConnectOptions
設(shè)置它,如下代碼:
To fire the OnAuthorizationCodeReceived
the event, we should use the hybrid flow which's 'response_type' parameter contains code
value.(eg. id_token code
). And we need set it through the OpenIdConnectOptions
like code below:
.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);
},
};
這篇關(guān)于ASP.NET Core 2.0 AzureAD 身份驗(yàn)證不起作用的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!