You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 03:18:03