C# 使用具有IdentityServer3隐式流的ASP.NET角色授权

C# 使用具有IdentityServer3隐式流的ASP.NET角色授权,c#,authorization,asp.net-core,identityserver3,C#,Authorization,Asp.net Core,Identityserver3,我的单页应用程序使用OidcTokenManager使用隐式流连接到IdentityServer3 STS。客户端将IDS3访问令牌作为承载令牌呈现给ASP.NET核心(WebApi)web服务;web服务应用程序配置为使用IDS3中间件,并使用Authorize属性限制对其方法的访问 SPA客户端配置: new Scope { Name = "BNApi", DisplayName = "BN Api", Enabled = true,

我的单页应用程序使用OidcTokenManager使用隐式流连接到IdentityServer3 STS。客户端将IDS3访问令牌作为承载令牌呈现给ASP.NET核心(WebApi)web服务;web服务应用程序配置为使用IDS3中间件,并使用Authorize属性限制对其方法的访问

SPA客户端配置:

new Scope
    {
        Name = "BNApi",
        DisplayName = "BN Api",
        Enabled = true,
        Type = ScopeType.Resource,
        Claims = new List<ScopeClaim>
        {
            new ScopeClaim(Constants.ClaimTypes.Name),
            new ScopeClaim(Constants.ClaimTypes.Role)
        }
    }
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = Configuration["Authority"],
        RequiredScopes = new[] {"BNApi"},
        NameClaimType = IdentityModel.JwtClaimTypes.Name,                
        RoleClaimType = IdentityModel.JwtClaimTypes.Role
    });
[Authorize]
public IActionResult Get()
{
    ...
}
函数配置令牌管理器(){
log(“configureTokenManager()”);
变量配置={
authority:$config.authority,
客户端id:“BNRegistry”,
重定向uri:$config.webRoot+“/#/authorized/”,
post_logout_redirect_uri:$config.webRoot+“/#/”,
响应类型:“id\U令牌”,
范围:“openid配置文件电子邮件BNApi”,
静默重定向uri:$config.webRoot+“/#/renew/”,
沉默的人:是的,
过滤协议声明:错误
};
返回新的管理器(配置);
};
STS中的作用域配置:

new Scope
    {
        Name = "BNApi",
        DisplayName = "BN Api",
        Enabled = true,
        Type = ScopeType.Resource,
        Claims = new List<ScopeClaim>
        {
            new ScopeClaim(Constants.ClaimTypes.Name),
            new ScopeClaim(Constants.ClaimTypes.Role)
        }
    }
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = Configuration["Authority"],
        RequiredScopes = new[] {"BNApi"},
        NameClaimType = IdentityModel.JwtClaimTypes.Name,                
        RoleClaimType = IdentityModel.JwtClaimTypes.Role
    });
[Authorize]
public IActionResult Get()
{
    ...
}
WebApi方法:

new Scope
    {
        Name = "BNApi",
        DisplayName = "BN Api",
        Enabled = true,
        Type = ScopeType.Resource,
        Claims = new List<ScopeClaim>
        {
            new ScopeClaim(Constants.ClaimTypes.Name),
            new ScopeClaim(Constants.ClaimTypes.Role)
        }
    }
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = Configuration["Authority"],
        RequiredScopes = new[] {"BNApi"},
        NameClaimType = IdentityModel.JwtClaimTypes.Name,                
        RoleClaimType = IdentityModel.JwtClaimTypes.Role
    });
[Authorize]
public IActionResult Get()
{
    ...
}
这与预期的一样,拒绝使用401密码的未经身份验证的用户。如果我在api控制器方法中检查用户的声明(例如,
user.claims.ToList()
),它包含用户已分配到的任何角色的条目

但是,如果检查
User.Identity.Name
属性,则该属性始终为空;如果查询
User.IsInRole(“管理员”)
则该属性始终为假,即使用户被分配到该角色。此外,如果我在
授权
属性(
[Authorize(role=“Administrator”)]
中添加角色名称,则无论用户是否属于所述角色,都将使用401拒绝用户


如何让IdentityServer 3与ASP.NET角色授权配合使用?

您是否尝试过重置
InboundClaimTypeMap

从IdentityServer3文档页面:

当您检查about页面上的声明时,您会注意到两个 事情:有些声明有奇数长的类型名,还有更多的声明 而不是应用程序中可能需要的

长长的声明名称来自微软的JWT处理程序试图映射 某些声明类型与.NET的ClaimTypes类类型相同

不幸的是,这种映射最终会破坏您定义为
name
role
的特定声明名称,因为它们的名称会被转换,不再映射到您期望的名称。这会导致
[Authorize(Roles=“”)]
用户.IsInRole(“”)
无法按预期工作

在API
Startup.cs
中,应添加以下内容:

JwtSecurityTokenHandler.InboundClaimTypeMap=new Dictionary();
app.useIdentityServerBearTokenauthentication(新的IdentityServerBearTokenauthenticationOptions()
{
...
});

编辑:以下信息不正确!。正如@Paul Taylor所指出的,“AlwaysInclude
属性确保相关声明始终存在于标识令牌中(与客户端而不是API一起使用)。这是一个资源范围,因此属性无效。”。感谢您帮助我进一步了解IdentityServer的工作原理:-)

对于访问API时要包含的
名称
角色
声明,您需要在
范围声明
列表中将其明确标记为
始终包含

新范围
{
Name=“BNApi”,
DisplayName=“BN Api”,
启用=真,
Type=ScopeType.Resource,
索赔=新名单
{

new ScopeClaim(Constants.ClaimTypes.Name,true),//谢谢@Jamie Dunstan,但是,AlwaysInclude属性确保相关声明始终存在于标识令牌中(用于客户端,而不是API)。这是一个资源范围,因此属性无效。啊,我很抱歉。我的配置是这样的,并假定它是解决方案。您是否尝试重置
InboundClaimTypeMap
?即添加
JwtSecurityTokenHandler.InboundClaimTypeMap=new Dictionary();
就在
app.UseIdentityServerBearerTokenAuthentication(…
在您的API
Startup.cs
?谢谢!这启用了IsInRole(“管理员”)和[Authorize(Roles=“Administrator”)]功能性。User.Identity.Name属性仍然是空的。很遗憾。有什么想法吗?你的应用程序中有这个功能吗?@PaulTaylor-My
User.Identity.Name
有效是的。我假设你有一个名为“Name”的声明?如果有,你如何添加此声明?@JamieDunstanMar,我没有,这就是问题所在。非常感谢。