SpringBoot通用OAuth2客户端集成Keycloak未返回映射角色为Authorities问题
解决方案
完全可以通过通用OAuth2配置实现自定义角色获取,只需完成两端配置即可:
步骤1:Keycloak侧配置角色映射
Keycloak默认不会将realm级别角色放入返回给OAuth2客户端的Token声明中,需要手动配置映射规则:
- 进入你创建的
myrealm域,左侧菜单选择「Client Scopes」,找到你配置中请求的roles范围并点击进入 - 切换到「Mappers」标签页,点击「Add Builtin」按钮,勾选内置的
realm roles映射器完成添加 - 进入刚添加的
realm roles映射器配置页,确认Add to ID token、Add to access token两个开关均为开启状态,默认的Token Claim Name为realm_access.roles,无需修改
步骤2:Spring Boot侧自定义权限映射
Spring Security默认的OAuth2权限转换器不会主动读取realm_access.roles字段生成权限,需要自定义权限映射逻辑:
1. 自定义权限映射器
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.GrantedAuthoritiesMapper; import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority; import java.util.*; import java.util.stream.Collectors; public class KeycloakRoleAuthoritiesMapper implements GrantedAuthoritiesMapper { @Override public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) { Set<GrantedAuthority> allAuthorities = new HashSet<>(); // 保留原有默认生成的SCOPE_*、ROLE_USER权限 allAuthorities.addAll(authorities); authorities.forEach(authority -> { if (authority instanceof OidcUserAuthority oidcAuthority) { // 从ID Token中读取realm角色声明 Map<String, Object> realmAccess = oidcAuthority.getIdToken().getClaim("realm_access"); if (realmAccess != null && realmAccess.containsKey("roles")) { List<String> roles = (List<String>) realmAccess.get("roles"); // 生成角色权限,如需适配Spring Security默认的ROLE_前缀规则,可替换为.map(role -> new SimpleGrantedAuthority("ROLE_" + role)) allAuthorities.addAll(roles.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList())); } } }); return allAuthorities; } }
2. 注册映射器到Security配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.core.GrantedAuthoritiesMapper; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class OAuth2SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2Login(oauth2Config -> oauth2Config .userInfoEndpoint(endpointConfig -> endpointConfig .userAuthoritiesMapper(keycloakAuthoritiesMapper()) ) ); return http.build(); } @Bean public GrantedAuthoritiesMapper keycloakAuthoritiesMapper() { return new KeycloakRoleAuthoritiesMapper(); } }
配置完成后重新启动应用,再次调用SecurityContextHolder.getContext().getAuthentication().getAuthorities()即可获取到Member、PremiumMember自定义角色。如果在映射时添加了ROLE_前缀,可直接通过Spring Security的@PreAuthorize("hasRole('Member')")注解做权限校验;未加前缀则使用@PreAuthorize("hasAuthority('Member')")校验即可。
内容的提问来源于stack exchange,提问作者K. Siva Prasad Reddy
相关产品推荐
相关产品推荐

