ASP.NET Core 2.2 中的 Azure AD 身份验证
Posted
技术标签:
【中文标题】ASP.NET Core 2.2 中的 Azure AD 身份验证【英文标题】:Azure AD Authentication in ASP.NET Core 2.2 【发布时间】:2019-12-13 03:13:59 【问题描述】:我目前正在努力将 ASP.NET Core 2.2 Web API 连接到现有的 Azure AD。我的配置基于 ASP.NET Core 团队的 this sample code。 Cookie 已替换为 JWT。
无法从元数据地址检索文档
现在我遇到以下错误消息:
IOException: IDX10804: Unable to retrieve document from: MetadataAdress.
- Microsoft.IdentityModel.Protocols.HttpDocumentRetriever+<GetDocumentAsync>d__8.MoveNext()
- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
- System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
- Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever
+<GetAsync>d__3.MoveNext()
- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
- System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
- Microsoft.IdentityModel.Protocols.ConfigurationManager+<GetConfigurationAsync>d__24.MoveNext()
当我直接调用 URL 时,我会收到包含配置文件的即时响应。但是,代码似乎无法做到这一点。我不确定是什么原因。
Azure AD 配置语法
此问题的最可能原因是配置错误。也许我弄错了字段的语法或遗漏了一个重要的值。
连接信息字段
连接信息字段的提供方式如下:
TenantId: Tenant-GUID
Authority: https://login.microsoftonline.com/TenantId
Resource: https://resource-endpoint.resource-domain
ClientId: Client-GUID
ClientSecret: ClientSecret
服务配置
Startup.cs
中的认证服务配置如下:
services
.AddAuthentication(options =>
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
)
.AddJwtBearer()
.AddOpenIdConnect(options =>
options.ClientId = this.ClientId;
options.ClientSecret = this.ClientSecret;
options.Authority = this.Authority;
options.Resource = this.Resource;
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.SignedOutRedirectUri = "/signed-out";
options.Events = new OpenIdConnectEvents()
OnAuthorizationCodeReceived = async context =>
var request = context.HttpContext.Request;
var currentUri = UriHelper.BuildAbsolute(
request.Scheme, request.Host, request.PathBase, request.Path
);
var credentials = new ClientCredential(this.ClientId, this.ClientSecret);
var authContext = new AuthenticationContext(
this.Authority,
AuthPropertiesTokenCache.ForCodeRedemption(context.Properties)
);
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.ProtocolMessage.Code,
new System.Uri(currentUri),
credentials,
this.Resource
);
context.HandleCodeRedemption(result.AccessToken, result.IdToken);
;
// Custom
options.MetadataAddress = $"this.Authority/federationmetadata/2007-06/federationmetadata.xml";
options.RequireHttpsMetadata = false; // Dev env only
现有 API
有很多现有的 Web API 连接到这个 Azure AD。遗憾的是,他们都在使用完整的 .NET Framework。他们使用来自Microsoft.Owin.Security.ActiveDirectory
命名空间的WindowsAzureActiveDirectoryBearerAuthenticationExtensions
的UseWindowsAzureActiveDirectoryBearerAuthentication
方法。
他们使用的另一件事是HostAuthenticationFilter
,其身份验证类型为Bearer
。
问题
有什么问题?
我该如何解决这个问题?
如何将这些组件一起使用?
ASP.NET Core 2.2 JWT 承载认证 Azure AD(仅令牌验证 + 声明提取 - 创建由其他服务处理)【问题讨论】:
【参考方案1】:您正在使用 OpenIDConnect
库并将它们指向 WS-Federation 元数据 (/federationmetadata/2007-06/federationmetadata.xml
)。这是行不通的。
OpenIDConnect 的正确元数据端点是 /.well-known/openid-configuration
。这是described here。首先更改它,然后返回 cookie。
更新
我监督的是,您正在保护 WebAPI。您说中间件使用JwtBearer
作为默认身份验证方案,但您还包括一个挑战方案为OIDC
。这对我来说真的没有意义。为什么要为 WebAPI 提供 OIDC 质询方案?
在这里您可以找到 ASP.NET Core 示例about JwtBearer。这里是Azure AD samples demoing WebApp calling WebApi(也是WebAPI的承载者,应用前端的OIDC。
没有使用 OIDC 质询的 JWT Bearer Auth 示例。你为什么要实现它?这是什么情况?您可能正在考虑实现多个身份验证方案,这是可能的。但是没有一种用于身份验证的方案和另一种用于质询的方案...
如果通过更新/删除错误的元数据更改了错误消息,请将其包含在您的原始问题中。就像现在一样 - 纯粹的错误消息是 OIDC 中间件无法解析 WS-Federation 元数据。这是预期的。
【讨论】:
关于元数据:我同意这感觉不对。可悲的是,删除它并没有什么不同,除了错误消息中显示的 url。我保留了它,因为以前的 API 仍在使用它。 cookie 中间件只是一种传输机制。如果用户身份是通过 cookie 或 JWT 不记名令牌传输的,则应该不相关。它们都包含相同的信息 - 因此,如果配置正确,它应该检测授权标头中的令牌,对其进行验证并从中提取用户身份。 你对这两者的结合有一个有效的观点。我的猜测是原作者确实想要JwtBearer
身份验证,但混淆了一些概念。我已经删除了 OIDC
中间件并验证了正确的行为。【参考方案2】:
问题的根源
经过一些测试,我设法确定了问题:显然这个问题的主要原因是网络相关。当我从我们公司切换到不受限制的网络时,身份验证成功。
修复
我必须配置一个代理并将其提供给JwtBearer
和OpenIdConnect
中间件。这看起来像这样:
var proxy = new HttpClientHandler
Proxy = new WebProxy("ProxyUrl:ProxyPort") UseDefaultCredentials = true; ,
UseDefaultCredentials = true
;
services
.AddJwtBearer(options =>
// ... other configuration steps ...
options.BackchannelHttpHandler = proxy;
)
.AddOpenIdConnect(options =>
// ... other configuration steps ...
options.BackchannelHttpHandler = proxy;
)
元数据地址
@astaykov 是正确的,元数据地址确实不正确。我也有这种感觉,但由于以前的 API 可以成功运行,所以我一直保持这种感觉。在问题测试期间,我也将其删除,但由于网络问题,它不会产生影响。
网络问题解决后,使用默认元数据地址即可。自定义失败 - 使用不同的身份验证架构时符合预期。
【讨论】:
以上是关于ASP.NET Core 2.2 中的 Azure AD 身份验证的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 2.2 - 密码重置在 Azure 上不起作用(无效令牌)
ASP.NET Core 应用程序日志未写入 Azure 应用服务中的 Blob
获取 ASP.NET-Core 2.2 控制器中的控制器名称和方法名称
ASP.NET Core在Azure Kubernetes Service中的部署和管理
Azure AD 与 ASP.NET Core MVC 中的标识
Azure Service Fabric 中 ASP.NET Core 应用程序中的 WebpackDevMiddleware