我想用IdentityServer4 Hybrid实现多个基于角色的授权,一切都很好,但是当我想这样使用时:
[Authorize(Roles = "Admin,SalaryUser")]
它不允许我访问并被拒绝。
在我的情况下,用户具有多个角色,如果一个角色有效,则控制器应向我授予访问权限,例如,在上述代码中,控制器应向这些用户授予访问权限: 用户具有SalaryUser角色,用户具有admin角色,用户同时具有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();
});
答案 0 :(得分:0)
您需要将JWT声明类型映射到Identity使用的声明类型。
当前的问题是ASP.NET Core的身份系统依赖于
ClaimTypes.Role
常量
(http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role)到
确定用户的角色。但是,索赔的名称表明
与OpenID JWT令牌上的角色相对应的就是role
。任何
当您需要合并OIDC身份和ASP.NET身份时,您必须进行翻译
这样的主张。
我稍微重写了您的代码,因为您可以使用声明标识而不使用JTokenType。尽管我没有时间对此进行全面测试,所以如果不这样做,则请坚持使用您的代码,但在向身份添加声明时将“ role”替换为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()
答案 1 :(得分:0)
您无需使用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"),