Web applications 将OpenIdConnect和JWT承载令牌与Microsoft Identity Web ASP.NET Core 3.1一起使用

Web applications 将OpenIdConnect和JWT承载令牌与Microsoft Identity Web ASP.NET Core 3.1一起使用,web-applications,asp.net-identity,asp.net-core-webapi,Web Applications,Asp.net Identity,Asp.net Core Webapi,我想让某人能够使用OpenIdConnect或使用OAuth 2.0授权码流(使用承载令牌)在浏览器中访问我的API。这与我在MicrosoftD365 OData端点中看到的功能类似。我可以通过浏览器访问它们,但它们需要用户身份验证,或者我可以使用承载令牌通过HTTP GET访问它们 如果我这样配置Web API: services.AddProtectedWebApi(this.Configuration). AddSignIn(this.Configuration); services.

我想让某人能够使用OpenIdConnect或使用OAuth 2.0授权码流(使用承载令牌)在浏览器中访问我的API。这与我在MicrosoftD365 OData端点中看到的功能类似。我可以通过浏览器访问它们,但它们需要用户身份验证,或者我可以使用承载令牌通过HTTP GET访问它们

如果我这样配置Web API:

services.AddProtectedWebApi(this.Configuration).
AddSignIn(this.Configuration);
services.AddProtectedWebApi(this.Configuration);
我可以从浏览器访问GET API,如果我尚未通过身份验证,它将提示我输入凭据并对我进行身份验证。但是,如果我尝试使用承载令牌从Postman访问相同的API,它将返回一个用于身份验证的网页

如果我这样配置Web API:

services.AddProtectedWebApi(this.Configuration).
AddSignIn(this.Configuration);
services.AddProtectedWebApi(this.Configuration);
我在浏览器中遇到401错误,但我可以使用承载令牌从Postman访问API

如果提供了承载令牌,我希望能够使用该令牌,否则将挑战用户凭据


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

我通过将方案添加到控制器上的
[Authorize]
属性中解决了这个问题。我将属性更改为
[Authorize(AuthenticationSchemes=OpenIdConnectDefaults.AuthenticationScheme+,“+JWTBeaerDefaults.AuthenticationScheme)]
,这将允许我在浏览器中进行身份验证(通过登录D365或office),然后为API对我进行身份验证。如果我使用承载令牌从Postman调用API,它也将成功进行身份验证

我确实看到一种奇怪的行为。如果我尚未在浏览器中进行身份验证(或者如果我启动了匿名会话),我将不再被提示输入我的凭据,并收到401结果。但是,如果我用
[Authorize]
[Authorize(AuthenticationSchemes=OpenIdConnectDefaults.AuthenticationScheme]
装饰控制器,浏览器将提示我并成功验证,但邮递员将收到登录页,而不是通过承载令牌进行验证

我还注意到,
iaAuthenticationSchemeProvider.GetRequestHandlerSchemesAsync()
总是返回
OpenIdConnectDefaults.AuthenticationScheme
作为请求方案。我感到奇怪的是,使用
JwtBearerDefaults.AuthenticationScheme
的邮差调用仍然返回
OpenIdConnectDefaults.AuthenticationScheme
作为请求方案


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

我通过将方案添加到控制器的
[Authorize]
属性中解决了这个问题。我将该属性更改为
[Authorize(authorizationschemes=OpenIdConnectDefaults.AuthenticationScheme+,“+jwtbearderdefaults.AuthenticationScheme)]
这将允许我在浏览器中进行身份验证(通过登录D365或office),然后为API对我进行身份验证。如果我使用承载令牌从邮递员处调用API,它也将成功进行身份验证

我确实看到了一个奇怪的行为。如果我还没有在浏览器中进行身份验证(或者如果我启动了一个匿名会话),我将不再被提示输入我的凭据,并收到一个401结果。但是,如果我用
[Authorize]
[Authorize(authorizationschemes=OpenIdConnectDefaults.authorizationscheme]装饰控制器
我将在浏览器中被提示并成功通过身份验证,但邮递员将收到一个登录页面,而不是通过承载令牌进行身份验证

我还注意到,
iaAuthenticationSchemeProvider.GetRequestHandlerSchemesAsync()
总是返回
OpenIdConnectDefaults.AuthenticationScheme
作为请求方案。我感到奇怪的是,使用
JwtBearerDefaults.AuthenticationScheme
的邮差调用仍然返回
OpenIdConnectDefaults.AuthenticationScheme
作为请求方案


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

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

受此启发,我提出了以下建议:

Startup.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]
属性修饰它们,并通过我实现的类设置OpenIDConnect和JwtBearer身份验证方案,该类实现了
IControllerModelConvention
,其灵感来自于但应用了方案而不是策略(因为这不起作用).

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

受此启发,我提出了以下建议:

Startup.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]
属性修饰它们,并通过我实现的类设置OpenIDConnect和JwtBearer身份验证方案,该类实现了
IControllerModelConvention
,受其启发,但应用了方案而不是策略(因为这不起作用)