![](/img/trans.png)
[英]How to Navigate to Custom Access Denied Page when AD Authentication failed for user (.net 3.1 core with OpenIDConnect Azure AD Authentication)
[英]How to exchange authorization code for access_token using Azure AD Authentication and OpenIdConnect in .NET Core 2.1?
我是多租户应用程序的新手,并且已经搜索了几天关于如何在.NET Core 2.1 中本地获取 access_token 。 到目前为止,我发现的所有内容都是 2.0 或更早版本,并且发布的任何方法都不存在于 2.1 中。
我创建了一个 Microsoft Graph 助手,它接受一个字符串access_token
并将获取用户详细信息。 我只是尝试在收到授权代码(OnAuthorizationCodeReceived 事件)后使用access_token
调用帮助程序。
我觉得这最多应该是一个单行或简短的片段,我似乎无法找到解决方案。
这是我希望发生这种情况的 Azure AD 扩展:
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Authentication
{
public static class AzureAdAuthenticationBuilderExtensions
{
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
=> builder.AddAzureAd(_ => { });
public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
builder.AddOpenIdConnect();
return builder;
}
private class ConfigureAzureOptions: IConfigureNamedOptions<OpenIdConnectOptions>
{
private readonly AzureAdOptions _azureOptions;
public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
{
_azureOptions = azureOptions.Value;
}
public void Configure(string name, OpenIdConnectOptions options)
{
options.ClientId = _azureOptions.ClientId;
options.Authority = $"{_azureOptions.Instance}";
options.UseTokenLifetime = true;
options.CallbackPath = _azureOptions.CallbackPath;
options.RequireHttpsMetadata = true;
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.IssuerValidator = ValidateIssuer;
options.Events.OnAuthenticationFailed = AuthenticationFailed;
options.Events.OnAuthorizationCodeReceived = AuthorizationCodeReceived;
}
// TODO check tenant against database for authorized tenants
private string ValidateIssuer(string issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (false)
{
//throw new SecurityTokenInvalidIssuerException();
// how do i get my db context here if there's no context in the scope?
// var db = context.HttpContext.RequestServices.GetRequiredService<RdmsContext>(); <-- something like this
}
// allowed
return issuer;
}
private static Task AuthenticationFailed(
AuthenticationFailedContext context)
{
context.HandleResponse();
string message = Uri.EscapeUriString(context.Exception.Message);
context.Response.Redirect($"/Home/Error?message={message}");
return Task.CompletedTask;
}
private static async Task AuthorizationCodeReceived(
AuthorizationCodeReceivedContext context)
{
string authorizationCode = context.ProtocolMessage.Code;
string idToken = context.ProtocolMessage.IdToken;
// ProtocolMessage has AccessToken property, but it's null.
// Exchange authorization code for access_token here
string accessToken = ...
var userDetails = MyProject.Helpers.Graph
.GetUserDetailsAsync(accessToken);
context.HandleCodeRedemption(accessToken, idToken);
}
public void Configure(OpenIdConnectOptions options)
{
Configure(Options.DefaultName, options);
}
}
}
}
经过大量的反复试验,我终于找到了缺失的部分。
首先,我将options.ResponseType
更改为OpenIdConnectResponseType.IdTokenToken
,据我所知,它返回一个 IdToken 以及一个令牌(访问令牌)。 这需要提供将使用访问令牌的资源。
因此,我还添加了值为"https://graph.microsoft.com"
options.Resource
。
我还删除了options.GetClaimsFromUserInfoEndpoint = true;
我还必须更新 Azure 中的应用程序清单以将oauth2AllowImplicitFlow
更改为true
。
最后,我取代了OnAuthorizationCodeRecevied
事件与OnTokenValidated
从我打电话给我的Microsoft Graph帮助的地步。
这种更改组合导致成功接收访问令牌,然后我可以将其提供给我的 Microsoft Graph 帮助程序并获得我需要的内容。
最终的Configure
方法现在看起来像这样:
public void Configure(string name, OpenIdConnectOptions options)
{
options.ClientId = _azureOptions.ClientId;
options.Resource = "https://graph.microsoft.com";
options.Authority = $"{_azureOptions.Instance}";
options.UseTokenLifetime = true;
options.CallbackPath = _azureOptions.CallbackPath;
options.RequireHttpsMetadata = true;
options.ResponseType = OpenIdConnectResponseType.IdTokenToken;
options.SaveTokens = true;
options.TokenValidationParameters.ValidateIssuer = true;
options.TokenValidationParameters.IssuerValidator = ValidateIssuer;
options.Events.OnAuthenticationFailed = AuthenticationFailed;
options.Events.OnTokenValidated = TokenValidatedAsync;
}
并且TokenValidatedAsync
现在具有在TokenValidatedContext.ProtocolMessage.AccessToken
找到的访问令牌:
private static async Task TokenValidatedAsync(
TokenValidatedContext context)
{
string accessToken = context.ProtocolMessage.AccessToken;
Graph.User userDetails = await MyProject.Helpers.Graph
.GetUserDetailsAsync(accessToken);
}
从这里我可以使用 Microsoft Graph 用户详细信息执行我需要的操作。
我找不到任何工作示例,因此我将其留在这里以供将来参考。
非常感谢,我想知道如何获取 Microsoft 图形的 access_token,但我使用的是 Microsoft.AspNetCore.Authentication.AzureAD.UI(它抽象了所有 OpenId 配置),我认为options.UseTokenLifetime = true
和options.SaveTokens = true;
帮助访问context.ProtocolMessage.AccessToken
再次感谢你
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.