将 OpenIdConnect 和 JWT Bearer Token 与 Microsoft Identity Web



我想为某人提供使用 OpenIdConnect 或使用持有者令牌使用 OAuth 2.0 授权代码流在浏览器中访问我的 API 的功能。这与我在 D365 OData 终结点中看到的功能类似Microsoft。我可以通过浏览器访问它们,但它们需要用户身份验证,或者我可以通过带有持有者令牌的 HTTP GET 访问它们。

如果我像这样配置 Web API:

services.AddProtectedWebApi(this.Configuration).
AddSignIn(this.Configuration);

我可以从浏览器访问 GET API,如果我尚未通过身份验证,它将提示我输入凭据并对我进行身份验证。但是,如果我尝试使用持有者令牌从 Postman 访问相同的 API,它会返回一个用于身份验证的网页。

如果我像这样配置 Web API:

services.AddProtectedWebApi(this.Configuration);

我在浏览器中收到 401 错误,但我能够使用持有者令牌从 Postman 访问 API。

我希望能够使用持有者令牌(如果已提供(,否则会质疑用户凭据。

我的控制器用户[Authorize],我当前未在 GET 操作中使用任何验证。我让中间件完成所有验证。

我已经通过将方案添加到控制器上的[Authorize]属性来解决此问题。我将属性更改为[Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme + "," + JwtBearerDefaults.AuthenticationScheme)],这将允许我在浏览器中进行身份验证(通过登录 D365 或办公室(,然后对我进行身份验证。如果我使用持有者令牌从 Postman 调用 API,它也将成功进行身份验证。

我确实看到了一种奇怪的行为。如果我尚未在浏览器中进行身份验证(或者如果我启动隐身会话(,则系统将不再提示我输入凭据,并且会收到 401 结果。但是,如果我用[Authorize][Authorize(AuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme]装饰控制器,我将在浏览器中收到提示并成功进行身份验证,但 Postman 将收到登录页面,而不是由持有者令牌进行身份验证。

我还注意到IAuthenticationSchemeProvider.GetRequestHandlerSchemesAsync()总是返回OpenIdConnectDefaults.AuthenticationScheme作为请求方案。对我来说很奇怪的是,来自邮递员的调用仍然返回JwtBearerDefaults.AuthenticationScheme仍然返回OpenIdConnectDefaults.AuthenticationScheme作为请求方案。

我希望这对其他人有所帮助。

过去一周我一直在调查这个完全相同的问题,并遇到了您在更新帖子中描述的相同 401 问题。我想我今天可能遇到了突破。

受到 https://github.com/aspnet/Security/issues/1469#issuecomment-399239254 的启发,我想出了以下内容:

启动.cs

services.AddProtectedWebApi(
options =>
{
Configuration.Bind("AzureAd", options);
options.ForwardDefaultSelector = (context =>
{
var authHeader = context.Request.Headers["Authorization"].ToArray();
if (authHeader.Length > 0 && authHeader[0].StartsWith("Bearer "))
{
return JwtBearerDefaults.AuthenticationScheme;
}
return OpenIdConnectDefaults.AuthenticationScheme;
});
},
configureMicrosoftIdentityOptions: options => Configuration.Bind("AzureAd", options),
tokenDecryptionCertificate: certificate
);
services.AddSignIn(Configuration);

然后对于我的控制器,我用[Authorize]属性装饰了它们,并通过我实现的实现IControllerModelConvention的类设置 OpenIDConnect 和 JwtBearer 身份验证方案,受 https://joonasw.net/view/apply-authz-by-default 启发,但应用方案而不是策略(因为这不起作用(。

我通过显式设置AddJwtBearer让它在 .NET 7 应用程序中工作:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
var conf = new MicrosoftIdentityOptions();
builder.Configuration.GetSection(Constants.AzureAd).Bind(conf);

opt.Audience = $"api://{conf.ClientId}";
opt.Authority = $"{conf.Instance}{conf.TenantId}";
})
.AddMicrosoftIdentityWebApp(builder.Configuration);

然后 API 控制器需要知道方案

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class SampleController : ControllerBase
...

相关内容

最新更新