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

Spring Boot 3.1 OAuth2资源服务器Actuator权限配置异常

问题排查与解决

核心原因分析

从日志中ROLE_[admin]的角色格式可以看出,Spring Security在解析JWT中的角色时,错误地将Keycloak返回的数组类型角色直接做了字符串转换——把["admin"]转成了[admin],再加上默认的ROLE_前缀,最终得到ROLE_[admin],而你的权限控制规则是针对ROLE_admin或admin,自然匹配失败。

解决方案步骤

1. 自定义JWT角色转换器,正确解析数组角色

创建自定义转换器处理Keycloak返回的数组格式角色:

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public class KeycloakJwtRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
    @Override
    public Collection<GrantedAuthority> convert(Jwt jwt) {
        Map<String, Object> realmAccess = jwt.getClaim("realm_access");
        if (realmAccess == null || !realmAccess.containsKey("roles")) {
            return List.of();
        }
        List<String> roles = (List<String>) realmAccess.get("roles");
        return roles.stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .toList();
    }
}

2. 在Security配置中应用转换器,覆盖Actuator权限规则

修改资源服务器配置,注入自定义转换器,并针对Actuator的自定义路径配置权限:

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.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class ResourceServerConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new KeycloakJwtRoleConverter());

        http
                .authorizeHttpRequests(auth -> auth
                        // 自定义Actuator路径权限:允许ROLE_admin访问
                        .requestMatchers("/your-custom-actuator/**").hasRole("admin")
                        // 其他API的权限规则
                        .requestMatchers("/api/**").hasAnyRole("user", "admin")
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -> oauth2
                        .jwt(jwt -> jwt
                                .jwtAuthenticationConverter(jwtAuthenticationConverter)
                        )
                );
        return http.build();
    }
}

3. 确认Actuator配置正确性

检查application.yml(或application.properties)中Actuator的自定义路径、端口及端点暴露配置:

management:
  server:
    port: 9090 # 自定义Actuator端口
  endpoints:
    web:
      base-path: /your-custom-actuator # 自定义Actuator路径
      exposure:
        include: health,info,metrics # 根据需求调整暴露的端点

4. 验证角色转换结果

重启服务后,查看日志或调试确认用户授权角色变为ROLE_admin,此时AuthoritiesAuthorizationManager就能正确匹配权限规则。

额外注意点

  • 如果Keycloak角色存储在resource_access的客户端角色字段下,需调整转换器中的Claim路径。
  • 确保Spring Security、Keycloak依赖与Spring Boot 3.1版本兼容,避免版本冲突导致的解析异常。

内容的提问来源于stack exchange,提问作者B Randall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:48:27