У меня есть приложение, созданное с помощью .NET Core API, Keycloak и JWT Token.
Старая версия Keycloak, которую я использовал до сих пор, когда она создавала токен JWT, она записывала роли здесь в полезной нагрузке:
{
"user_roles": [
"offline_access",
"uma_authorization",
"admin",
"create-realm"
]
}
Но теперь, после того, как я его обновил, он пишет роли здесь, в полезной нагрузке:
{
"realm_access": {
"roles": [
"create-realm",
"teacher",
"offline_access",
"admin",
"uma_authorization"
]
},
}
И мне нужно знать, как изменить этот старый код на новый, чтобы сказать, что не смотрите на user_roles, а смотрите на realm_access, а затем на roles.
public void AddAuthorization(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("Administrator", policy => policy.RequireClaim("user_roles", "admin"));
options.AddPolicy("Teacher", policy => policy.RequireClaim("user_roles", "teacher"));
options.AddPolicy("Pupil", policy => policy.RequireClaim("user_roles", "pupil"));
options.AddPolicy(
"AdminOrTeacher",
policyBuilder => policyBuilder.RequireAssertion(
context => context.User.HasClaim(claim =>
claim.Type == "user_roles" && (claim.Value == "admin" || claim.Value == "teacher")
))
);
});
}





Следующий код преобразует претензию "realm_access.roles" (токен JWT) из Keycloak (v4.7.0) в утверждения роли Microsoft Identity Model:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
...
}
public class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
ClaimsIdentity claimsIdentity = (ClaimsIdentity)principal.Identity;
// flatten realm_access because Microsoft identity model doesn't support nested claims
// by map it to Microsoft identity model, because automatic JWT bearer token mapping already processed here
if (claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim((claim) => claim.Type == "realm_access"))
{
var realmAccessClaim = claimsIdentity.FindFirst((claim) => claim.Type == "realm_access");
var realmAccessAsDict = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(realmAccessClaim.Value);
if (realmAccessAsDict["roles"] != null)
{
foreach (var role in realmAccessAsDict["roles"])
{
claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
}
}
}
return Task.FromResult(principal);
}
}
Пожалуйста, добавьте объяснение того, что делает ваш код
Для будущих читателей - вы можете проанализировать любое значение заявки из JWT с помощью метода RequireAssertion.
services.AddAuthorization(options => options.AddPolicy("Administrator", policy =>
policy.RequireAssertion(c =>
JsonSerializer.Deserialize<Dictionary<string, string[]>>(c.User?.FindFirst((claim) => claim.Type == "realm_access")?.Value ?? "{}")
.FirstOrDefault().Value?.Any(v => v == "admin") ?? false)));
вложенные утверждения не поддерживаются используемой там моделью удостоверений Майкрософт (класс
Claimsне имеет опции / функции вложенных утверждений). Используйте плоскую структуру ("ключ-значение") из первого сегмента