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

Spring Security 6中如何自定义expressionHandler与accessDecisionManager

Spring Boot 3.x/Spring Security 6.x 配置自定义ExpressionHandler与AccessDecisionManager

在Spring Security 6.x中,WebSecurityConfigurerAdapter被废弃,转而使用SecurityFilterChain bean配置安全规则。原有的ExpressionInterceptUrlRegistry设置expressionHandler和accessDecisionManager的方式不再适用,以下是两种可行的配置方案:

方案一:替换默认的FilterSecurityInterceptor(贴近原有配置逻辑)

FilterSecurityInterceptor是Spring Security中负责最终授权决策的核心过滤器,我们可以自定义该过滤器的实例,注入自己的expressionHandler和accessDecisionManager,然后替换掉默认的过滤器。

1. 自定义WebSecurityExpressionHandler

@Component
public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {
    @Override
    protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
        WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
        // 这里添加自定义逻辑,比如设置自定义PermissionEvaluator
        root.setPermissionEvaluator(new CustomPermissionEvaluator());
        return root;
    }
}

2. 自定义AccessDecisionManager

@Component
public class CustomAccessDecisionManager extends AffirmativeBased {
    public CustomAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {
        super(decisionVoters);
        // 自定义配置,例如设置是否允许所有投票者弃权时通过
        setAllowIfAllAbstainDecisions(false);
    }
}

3. 配置SecurityFilterChain并替换FilterSecurityInterceptor

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final AuthenticationManager authenticationManager;
    private final CustomWebSecurityExpressionHandler expressionHandler;
    private final CustomAccessDecisionManager accessDecisionManager;

    // 构造注入依赖
    public SecurityConfig(AuthenticationManager authenticationManager,
                          CustomWebSecurityExpressionHandler expressionHandler,
                          CustomAccessDecisionManager accessDecisionManager) {
        this.authenticationManager = authenticationManager;
        this.expressionHandler = expressionHandler;
        this.accessDecisionManager = accessDecisionManager;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 定义URL授权规则:RequestMatcher对应权限表达式
        LinkedHashMap<RequestMatcher, Collection<String>> authRules = new LinkedHashMap<>();
        authRules.put(new AntPathRequestMatcher("/admin/**"), Collections.singletonList("hasRole('ADMIN')"));
        authRules.put(new AntPathRequestMatcher("/user/**"), Collections.singletonList("hasRole('USER')"));
        authRules.put(new AntPathRequestMatcher("/**"), Collections.singletonList("authenticated"));

        // 创建安全元数据源,绑定自定义expressionHandler
        DefaultFilterInvocationSecurityMetadataSource metadataSource =
                new DefaultFilterInvocationSecurityMetadataSource(authRules, expressionHandler);

        // 配置自定义FilterSecurityInterceptor
        FilterSecurityInterceptor customFilter = new FilterSecurityInterceptor();
        customFilter.setAuthenticationManager(authenticationManager);
        customFilter.setAccessDecisionManager(accessDecisionManager);
        customFilter.setSecurityMetadataSource(metadataSource);

        // 替换默认的FilterSecurityInterceptor
        http
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .addFilterBefore(customFilter, FilterSecurityInterceptor.class);

        return http.build();
    }

    // 提供WebExpressionVoter给自定义AccessDecisionManager(用于表达式投票)
    @Bean
    public WebExpressionVoter webExpressionVoter() {
        WebExpressionVoter voter = new WebExpressionVoter();
        voter.setExpressionHandler(expressionHandler);
        return voter;
    }
}

方案二:使用ExpressionAuthorizationManager(符合新授权模型)

Spring Security 6.x推荐使用AuthorizationManager接口处理授权逻辑,我们可以通过ExpressionAuthorizationManager整合自定义的expressionHandler和accessDecisionManager。

1. 自定义组件同方案一

复用方案一中的CustomWebSecurityExpressionHandler和CustomAccessDecisionManager。

2. 配置SecurityFilterChain

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CustomWebSecurityExpressionHandler expressionHandler;
    private final CustomAccessDecisionManager accessDecisionManager;

    public SecurityConfig(CustomWebSecurityExpressionHandler expressionHandler,
                          CustomAccessDecisionManager accessDecisionManager) {
        this.expressionHandler = expressionHandler;
        this.accessDecisionManager = accessDecisionManager;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // 构建自定义表达式授权管理器
        AuthorizationManager<RequestAuthorizationContext> customAuthManager =
                ExpressionAuthorizationManager.authenticated()
                        .expressionHandler(expressionHandler)
                        .accessDecisionManager(accessDecisionManager);

        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/admin/**").access(customAuthManager)
                        .requestMatchers("/user/**").access("hasRole('USER')") // 该表达式会使用全局配置的expressionHandler
                        .anyRequest().authenticated()
                )
                // 全局设置表达式处理器,确保所有表达式授权都使用自定义实现
                .securityContext(context -> context.expressionHandler(expressionHandler));

        return http.build();
    }

    @Bean
    public WebExpressionVoter webExpressionVoter() {
        WebExpressionVoter voter = new WebExpressionVoter();
        voter.setExpressionHandler(expressionHandler);
        return voter;
    }
}

两种方案各有优劣:方案一更贴近旧版配置逻辑,适合需要完全复用原有授权规则的场景;方案二更符合Spring Security 6.x的新设计理念,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:21:28