默认情况下,Spring Security 会生成一个列表GrantedAuthority
使用中的值scope
or scp
索赔和SCOPE_
prefix.
Keycloak 将领域角色保留在嵌套声明中realm_access.roles
。您有两种选择来提取角色并将其映射到列表GrantedAuthority
.
OAuth2客户端
如果您的应用程序配置为 OAuth2 客户端,则您可以从 ID 令牌或 UserInfo 端点提取角色。 Keycloak 仅在访问令牌中包含角色,因此您需要更改配置以将它们也包含在 ID 令牌或 UserInfo 端点中(这就是我在以下示例中使用的)。您可以从 Keycloak 管理控制台执行此操作,转至Client Scopes > roles > Mappers > realm roles
然后,在 Spring Security 配置中,定义一个GrantedAuthoritiesMapper
它从 UserInfo 端点提取角色并将它们映射到GrantedAuthority
s。在这里,我将介绍特定 bean 的外观。我的 GitHub 上提供了完整的示例:https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/login-user-authorities https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/login-user-authorities
@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
return authorities -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
var authority = authorities.iterator().next();
boolean isOidc = authority instanceof OidcUserAuthority;
if (isOidc) {
var oidcUserAuthority = (OidcUserAuthority) authority;
var userInfo = oidcUserAuthority.getUserInfo();
if (userInfo.hasClaim("realm_access")) {
var realmAccess = userInfo.getClaimAsMap("realm_access");
var roles = (Collection<String>) realmAccess.get("roles");
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
} else {
var oauth2UserAuthority = (OAuth2UserAuthority) authority;
Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();
if (userAttributes.containsKey("realm_access")) {
var realmAccess = (Map<String,Object>) userAttributes.get("realm_access");
var roles = (Collection<String>) realmAccess.get("roles");
mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
}
}
return mappedAuthorities;
};
}
Collection<GrantedAuthority> generateAuthoritiesFromClaim(Collection<String> roles) {
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
}
OAuth2 资源服务器
如果您的应用程序配置为 OAuth2 资源服务器,则您可以从访问令牌中提取角色。在 Spring Security 配置中,定义一个JwtAuthenticationConverter
bean 从访问令牌中提取角色并将它们映射到GrantedAuthority
s。在这里,我将介绍特定 bean 的外观。我的 GitHub 上提供了完整的示例:https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/resource-server-jwt-authorities https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/resource-server-jwt-authorities
public JwtAuthenticationConverter jwtAuthenticationConverterForKeycloak() {
Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter = jwt -> {
Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = realmAccess.get("roles");
return roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
};
var jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}