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
相关产品推荐
相关产品推荐

