【问题标题】:IdentityServer4 Role Based Authorization on multiple rolesIdentityServer4 基于角色的多个角色授权
【发布时间】:2019-10-05 07:26:00
【问题描述】:

我想用 IdentityServer4 混合实现多个基于角色的授权,一切都很好,但是当我想这样使用时:

[Authorize(Roles = "Admin,SalaryUser")]

它不允许我访问并拒绝访问。

在我的场景中,用户有多个角色,如果角色有效,控制器应该授予我访问权限,例如在上面的代码中,控制器应该授予这些用户访问权限: 用户具有 SalaryUser 角色,具有管理员角色的用户,用户同时具有 Admin、SalaryUser 角色。

这里是配置:

.AddOpenIdConnect("oidc", options =>
                    {
                        options.SignInScheme = "Cookies";

                        options.Authority = authority;
                        options.RequireHttpsMetadata = false;
                        options.ClientId = clientId;
                        options.ClientSecret = "secret";
                        options.ResponseType = "code id_token";
                        options.UseTokenLifetime = false;
                        options.SaveTokens = true;
                        options.GetClaimsFromUserInfoEndpoint = true;





                        options.ClaimActions.MapCustomJson("role", jobj =>
                        {
                            IEnumerable<string> values = jobj["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"].Values<string>();
                            StringBuilder sb = new StringBuilder();
                            foreach (string val in values)
                            {
                                sb.Append(val + ",");
                            }
                            return sb.ToString().TrimEnd(',');
                        });

                        options.Scope.Add("api1");
                        options.Scope.Add("offline_access");
                       // options.Scope.Add("roles");

                        options.Events = new OpenIdConnectEvents()
                        {

                            OnUserInformationReceived = async UserInformationReceivedContext =>
                            {
                                // UserInformationReceivedContext.User.Remove("address");

                                if (UserInformationReceivedContext.User.TryGetValue("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", out JToken role))
                                {
                                    var claims = new List<Claim>();
                                    if (role.Type != JTokenType.Array)
                                    {
                                        claims.Add(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", (string)role));
                                    }
                                    else
                                    {
                                        foreach (var r in role)
                                            claims.Add(new Claim("role", (string)r));
                                    }
                                    var id = UserInformationReceivedContext.Principal.Identity as ClaimsIdentity;
                                    id.AddClaims(claims);
                                }
                            }
                        };

                        options.ClaimActions.MapAll();
                    });

【问题讨论】:

标签: asp.net-core .net-core authorization identityserver4


【解决方案1】:

您无需使用 MapCustomJson 或您的 OnUserInformationReceived 手动映射声明。

如果 jwt 令牌中的声明是 role 而不是 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role ,您可以设置客户端应用的角色验证声明:

options.TokenValidationParameters = new TokenValidationParameters
{
    RoleClaimType = "role"
};

另一种方法是在身份服务器应用程序上向您颁发的令牌添加角色声明时,使用ClaimTypes.Role

new Claim(ClaimTypes.Role, "Admin"),

【讨论】:

    【解决方案2】:

    您需要将 JWT 声明类型映射到 Identity 使用的声明类型。

    目前的问题是 ASP.NET Core 的身份系统依赖于 ClaimTypes.Role 常量 (http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role) 到 确定用户的角色。然而,声称的名称 对应于 OpenID JWT 令牌上的角色只是 role。任何 当你需要合并 OIDC 身份和 ASP.NET 身份时,你必须翻译 像这样的索赔。

    我稍微重写了您的代码,因为您可以在不使用 JTokenType 的情况下使用声明身份。虽然我没有时间对此进行彻底测试,所以如果它不遵守您的代码,但在您向身份添加声明时将“角色”替换为 ClaimTypes.Role。

                OpenIdConnectEvents CreateOpenIdConnectEvents()
                {
                    return new OpenIdConnectEvents()
                    {
                        OnTicketReceived = context =>
                        {
                            var identity = context.Principal.Identity as ClaimsIdentity;
                            if (identity != null)
                            {
                                if (identity.HasClaim(c => c.Type == "role"))
                                {
                                    foreach (var role in identity.Claims.Where(c => c.Type == "role"))
                                    {
                                        if (!context.Principal.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == role.Value))
                                        {
                                            identity.AddClaim(new Claim(ClaimTypes.Role, role.Value));
                                        }
                                    }
                                }
    
                            }
                            return Task.FromResult(0);
                        }
                    };
                }
    

    这样使用:

    options.Events = new CreateOpenIdConnectEvents()
    

    【讨论】:

      猜你喜欢
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 2018-07-21
      相关资源
      最近更新 更多