如何解决IDW10201:在承载令牌中未找到范围或角色声明
我有一个ASP.NET Core 3.1项目,例如以下示例:Sign-in a user with the Microsoft Identity Platform in a WPF Desktop application and call an ASP.NET Core Web API。
我正在使用Identity web
1.0版和Azure AD单租户应用程序。
由于我只请求一个应用程序令牌,而不是一个用户令牌,所以我编辑了清单,添加了appRoles
:
[... more json ...]
"appId": "<guid>","appRoles": [
{
"allowedMemberTypes": [
"Application"
],"description": "Accesses the application.","displayName": "access_as_application","id": "<unique guid>","isEnabled": true,"lang": null,"origin": "Application","value": "access_as_application"
}
],"oauth2AllowUrlPathMatching": false,[... more json ...]
我还启用了idtyp
访问令牌声明,以指定这是一个应用程序令牌。
[... more json ...]
"optionalClaims": {
"idToken": [],"accesstoken": [
{
"name": "idtyp","source": null,"essential": false,"additionalProperties": []
}
],"saml2Token": []
[... more json ...]
以下请求是由邮递员提出的。请注意/.default
与范围的使用,在文档中有关client credentials grant flow提到了作用域。
POST /{tenant_id}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
scope=api%3A%2F%2{client_id}%2F.default
&client_id={client_id}
&grant_type=client_credentials
&client_secret={secret_key}
请求返回一个access_token
,可以用jwt.ms查看,并且看起来像这样,出于安全原因,实际数据已由占位符替换。:
{
"typ": "JWT","alg": "RS256","x5t": "[...]","kid": "[...]"
}.{
"aud": "api://<client_id>","iss": "https://sts.windows.net/<tenant_id>/","iat": 1601803439,"nbf": 1601803439,"exp": 1601807339,"aio": "[...]==","appid": "<app id>","appidacr": "1","idp": "https://sts.windows.net/<tenant_id>/","idtyp": "app","oid": "<guid>","rh": "[..].","roles": [
"access_as_application"
],"sub": "<guid>","tid": "<guid>","uti": "[...]","ver": "1.0"
}
我注意到上面的令牌不包含scp
。这似乎是正确的,因为这是应用程序令牌而不是用户令牌。相反,它包括“ roles”作为应用程序令牌的适当名称。
access_token
现在可以用作Postman Get中的载体:
GET /api/myapi
Host: https://localhost:5001
Authorization: Bearer {access_token}
对此请求的响应为500 internal error
。即出了点问题。 access_token
看起来像是一个应用程序令牌,因此错误似乎出在ASP.NET Core 3.1控制器端。
ASP.NET Core 3.1。托管自定义API的项目有一个startup.cs
,其中包含以下代码:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
// This is added for the sole purpose to highlight the origin of the exception.
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme,options =>
{
var existingOnTokenValidatedHandler = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
if (context.Principal.Claims.All(x => x.Type != ClaimConstants.Scope)
&& context.Principal.Claims.All(y => y.Type != ClaimConstants.Scp)
&& context.Principal.Claims.All(y => y.Type != ClaimConstants.Roles))
{
// This where the exception originates from:
throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
}
};
});
该项目的appsettings.json
包括:
"AzureAD": {
"Instance": "https://login.microsoftonline.com/","Domain": "mydomain.onmicrosoft.com","ClientId": "<client_id>","TenantId": "<tenant_id>","Audience": "api://<client_id>"
},
...,控制器如下所示:
[Authorize]
[Route("api/[controller]")]
public class MyApiController : Controller
{
[HttpGet]
public async Task<string> Get()
{
return "Hello World!";
}
}
500 internal error
的根本原因是引发了此异常:IDW10201: Neither scope or roles claim was found in the bearer token.
异常。
更新:
(有关更多详细信息,请参见下面的答案)。
有关“ Implementing Authorization in your Applications with Microsoft identity platform - june 2020”的视频建议,丢失的部分是该标志JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
,需要在startup.cs
中进行设置-例如:
public void ConfigureServices(IServiceCollection services)
{
// By default,the claims mapping will map clain names in the old format to accommodate older SAML applications.
//'http://schemas.microsodt.com/ws/2008/06/identity/clains/role' instead of 'roles'
// This flag ensures that the ClaimsIdentity claims collection will be build from the claims in the token
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
[...more code...]
解决方法
视频“ Implementing Authorization in your Applications with Microsoft identity platform - june 2020”概述缺少的片段是此标志JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
,需要在startup.cs
中设置-例如:
public void ConfigureServices(IServiceCollection services)
{
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
// By default,the claims mapping will map claim names in the old format to accommodate older SAML applications.
//'http://schemas.microsodt.com/ws/2008/06/identity/clains/role' instead of 'roles'
// This flag ensures that the ClaimsIdentity claims collection will be build from the claims in the token
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
// Notice that this part is different in the video,// however in this context the following seems to be
// the correct way of setting the RoleClaimType:
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme,options =>
{
// The claim in the Jwt token where App roles are available.
options.TokenValidationParameters.RoleClaimType = "roles";
});
[... more code ...]
}
替代1
还可以在startup.cs
中为整个应用设置授权:
services.AddControllers(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireClaim("roles","access_as_application")
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
替代2
也可以使用以下策略:
services.AddAuthorization(config =>
{
config.AddPolicy("Role",policy =>
policy.RequireClaim("roles","access_as_application"));
});
现在此策略可用于类似这样的控制器请求:
[HttpGet]
[Authorize(Policy = "Role")]
public async Task<string> Get()
{
return "Hello world!";
}
文档中的更多内容:Policy based role checks。
,只需将DefaultMapInboundClaims添加到您的API服务配置中
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
}
,
原因是您正在使用默认范围scope=api%3A%2F%2{client_id}%2F.default
发出请求,而默认范围inner class WeatherTask(var location: Location) : AsyncTask<String,Void,String>() {
在access_token中不包含范围声明,您应该使用已为ASP.NET Core 3.1 API项目注册的特定范围在Azure门户中公开该API。
如果您计划不使用构建作用域或角色,这可能会有所帮助。您可以使用下面针对Azure B2C的示例启用“访问控制列表”身份验证。这是官方文档的一些链接。
将以下内容添加到您的广告配置中:
"AllowWebApiToBeAuthorizedByACL": true
示例:
"AzureAdB2C": {
"Instance": "https://xxx.b2clogin.com/","ClientId": "xxxx","Domain": "xxx.onmicrosoft.com","SignUpSignInPolicyId": "xxx","AllowWebApiToBeAuthorizedByACL": true
},
关于ACL /访问控制列表的含义: ACL:https://en.wikipedia.org/wiki/Access-control_list
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。