Spring Security 6自定义表达式根未注册致@PreAuthorize方法调用报错
问题根源
你的自定义CustomMethodSecurityExpressionRoot未被生效,核心原因是**@EnableMethodSecurity没有关联你的自定义表达式处理器**,导致Spring Security依然使用默认的MethodSecurityExpressionRoot,自然找不到你自定义的hasRealmRole方法。
解决方案
方法一:通过@EnableMethodSecurity直接指定自定义处理器
将自定义表达式处理器的Bean定义整合到SecurityConfig中,并通过注解属性指定使用该处理器:
@Configuration @EnableMethodSecurity(expressionHandler = CustomMethodSecurityExpressionHandler.class) public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests(auth -> auth .requestMatchers("/health/**", "/swagger-ui/**", "/swagger/**", "/v3/api-docs/**", "/configuration/**").permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken); return http.build(); } @Bean public CustomMethodSecurityExpressionHandler customMethodSecurityExpressionHandler(RoleHierarchy roleHierarchy) { CustomMethodSecurityExpressionHandler handler = new CustomMethodSecurityExpressionHandler(); handler.setRoleHierarchy(roleHierarchy); return handler; } @Bean public RoleHierarchy roleHierarchy() { return new RoleHierarchyImpl(); } }
同时删除原有的BaseConfig类,避免Bean重复定义冲突。
方法二:保留独立配置类并关联处理器
如果希望拆分配置类,可按以下方式调整:
- 修改
BaseConfig,确保处理器Bean被Spring正确管理:
@Configuration public class BaseConfig { @Bean public RoleHierarchy roleHierarchy() { return new RoleHierarchyImpl(); } @Bean public CustomMethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) { var handler = new CustomMethodSecurityExpressionHandler(); handler.setRoleHierarchy(roleHierarchy); return handler; } }
- 在
SecurityConfig的@EnableMethodSecurity中指定自定义处理器:
@Configuration @EnableMethodSecurity(expressionHandler = CustomMethodSecurityExpressionHandler.class) public class SecurityConfig { // 原有securityFilterChain Bean逻辑不变 }
额外优化建议
在CustomMethodSecurityExpressionRoot中添加类型判断,避免潜在的类型转换异常:
public boolean hasRealmRole(String role) { if (!(getPrincipal() instanceof OAuth2AuthenticatedPrincipal principal)) { return false; } var realmAccess = (JSONObject)principal.getAttribute("realm_access"); if (realmAccess == null) { return false; } var roles = (JSONArray)realmAccess.get("roles"); return roles != null && roles.stream().anyMatch(x -> x.equals(role)); }
内容的提问来源于stack exchange,提问作者ghallas
相关产品推荐
相关产品推荐

