Asp.net core 如何在.NET Core 2.1中使用Azure AD身份验证和OpenIdConnect为access_令牌交换授权代码?
我是多租户应用的新手,几天来一直在谷歌上搜索如何在.NETCore2.1中本机获取access_令牌。到目前为止,我发现的所有内容都是2.0或更早版本,并且发布的方法都不存在于2.1中 我已经创建了一个Microsoft Graph helper,它接受一个字符串Asp.net core 如何在.NET Core 2.1中使用Azure AD身份验证和OpenIdConnect为access_令牌交换授权代码?,asp.net-core,.net-core,asp.net-core-mvc,microsoft-graph-api,asp.net-core-2.1,Asp.net Core,.net Core,Asp.net Core Mvc,Microsoft Graph Api,Asp.net Core 2.1,我是多租户应用的新手,几天来一直在谷歌上搜索如何在.NETCore2.1中本机获取access_令牌。到目前为止,我发现的所有内容都是2.0或更早版本,并且发布的方法都不存在于2.1中 我已经创建了一个Microsoft Graph helper,它接受一个字符串access\u token,并将获取用户详细信息。我只是在收到授权代码(OnAuthorizationCodeReceived事件)后,尝试使用access\u令牌调用帮助程序 我觉得这最多应该是一行或一小段,而我似乎找不到解决办法
access\u token
,并将获取用户详细信息。我只是在收到授权代码(OnAuthorizationCodeReceived事件)后,尝试使用access\u令牌
调用帮助程序
我觉得这最多应该是一行或一小段,而我似乎找不到解决办法
这是我的Azure广告扩展,我希望它能够实现:
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);
}
}
}
}
使用Microsoft.AspNetCore.Authentication.OpenIdConnect;
使用Microsoft.Extensions.DependencyInjection;
使用Microsoft.Extensions.Options;
使用Microsoft.IdentityModel.Protocols.OpenIdConnect;
使用Microsoft.IdentityModel.Tokens;
使用制度;
使用System.Threading.Tasks;
命名空间Microsoft.AspNetCore.Authentication
{
公共静态类AzureAdAuthenticationBuilderExtensions
{
公共静态AuthenticationBuilder AddAzureAd(此AuthenticationBuilder)
=>builder.AddAzureAd({});
公共静态AuthenticationBuilder AddAzureAd(此AuthenticationBuilder,操作配置选项)
{
builder.Services.Configure(配置选项);
builder.Services.AddSingleton();
AddOpenIdConnect();
返回生成器;
}
私有类配置AzureOptions:IConfigureNameOptions
{
私人只读AzureAdOptions _azureOptions;
公共配置azureOptions(IOptions azureOptions)
{
_azureOptions=azureOptions.Value;
}
public void配置(字符串名称、OpenIdConnectOptions选项)
{
options.ClientId=\u azureOptions.ClientId;
options.Authority=$“{u azureOptions.Instance}”;
options.UseTokenLifetime=true;
options.CallbackPath=\u azureOptions.CallbackPath;
options.RequireHttpsMetadata=true;
options.ResponseType=OpenIdConnectResponseType.CodeIdToken;
options.SaveTokens=true;
options.GetClaimsFromUserInfoEndpoint=true;
options.TokenValidationParameters.ValidateIsuer=true;
options.TokenValidationParameters.IssuerValidator=ValidateIssuer;
options.Events.OnAuthenticationFailed=身份验证失败;
options.Events.OnAuthorizationCodeReceived=AuthorizationCodeReceived;
}
//TODO根据数据库检查授权租户的租户
私有字符串ValidateSuer(字符串颁发者、SecurityToken SecurityToken、TokenValidationParameters validationParameters)
{
if(false)
{
//抛出新的SecurityTokenInvalidIssuerException();
//如果作用域中没有上下文,如何在此处获取db上下文?
//var db=context.HttpContext.RequestServices.GetRequiredService();经过多次尝试和错误,我终于找到了缺失的部分
首先,我将options.ResponseType
更改为OpenIdConnectResponseType.IdTokenToken
,据我所知,它返回一个IdToken以及一个令牌(访问令牌)。这需要提供一个资源,访问令牌将用于该资源
因此,我还添加了选项。Resource
的值为”https://graph.microsoft.com“
我还删除了options.GetClaimsFromUserInfoEndpoint=true;
我还必须更新Azure中的应用程序清单,以将oauth2AllowImplicitFlow
更改为true
最后,我用OnTokenValidated
替换了OnAuthorizationCodeReceived
事件,作为调用Microsoft Graph helper的起点
这些更改的组合导致成功接收访问令牌,然后我可以将其馈送给我的Microsoft Graph helper并获得我需要的内容
最后的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用户详细信息做我需要的事情
我找不到这方面的任何有效示例,因此我将把它留在这里供将来参考。经过多次尝试和错误,我终于找到了缺失的部分
首先,我将options.ResponseType
更改为OpenIdConnectResponseType.IdTokenToken
,据我所知,它返回一个IdToken以及一个令牌(访问令牌)。这需要提供一个资源,访问令牌将用于该资源
因此,我还添加了选项。Resource
的值为”https://graph.microsoft.com“
我还删除了options.GetClaimsFromUserInfoEndpoint=true;
我还必须更新Azure中的应用程序清单,以将oauth2AllowImplicitFlow
更改为true
最后,我用OnTokenValidated
替换了OnAuthorizationCodeReceived
事件,作为调用Microsoft Graph helper的起点
这些更改的组合导致成功接收访问令牌,然后我可以将其馈送给我的Microsoft Graph helper并获得我需要的内容
最后的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);
}
从这里我可以做什么