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

如何为已受Keycloak保护的接口添加自定义认证过滤器

问题:Spring Boot + Keycloak 自定义认证过滤器无法触发

我有一个通过KeycloakWebSecurityConfigurerAdapter保护的Spring Boot应用,现在想给部分端点添加另一种自定义认证方式。我已经创建了继承AbstractAuthenticationProcessingFilter和AuthenticationProvider的类并实现了自定义逻辑,之后尝试用下面的代码把自定义过滤器加到HttpSecurity里:

http.addFilterBefore(new VendorSessionAuthorizationFilter(), KeycloakAuthenticationProcessingFilter.class);

预期是自定义过滤器先执行,根据结果再进入Keycloak的过滤器链,但测试调用端点时,过滤器里的attemptAuthentication方法从未触发。感觉不管怎么调用http.addFilterBefore(...),Keycloak过滤器都会优先执行,导致自定义认证用不了。

我的SecurityConfiguration配置如下:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);

        http.addFilterBefore(new VendorSessionAuthorizationFilter(), KeycloakAuthenticationProcessingFilter.class);
        http.authenticationProvider(new VendorSessionAuthenticationProvider());

        http
                .cors().and()
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
                .and().formLogin().disable()
                .httpBasic().disable()
                .logout().disable()

                .authorizeRequests()
                .anyRequest().authenticated();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Bean
    public KeycloakConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
            KeycloakAuthenticatedActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
            KeycloakSecurityContextRequestFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(false);
        return registrationBean;
    }
}

原因分析

  1. 过滤器顺序错误:调用super.configure(http)后再添加自定义过滤器,此时Keycloak相关过滤器已经被初始化到链中,addFilterBefore无法正确将自定义过滤器插入到目标位置。
  2. 未指定拦截路径:AbstractAuthenticationProcessingFilter默认仅处理匹配特定路径的请求,若你的VendorSessionAuthorizationFilter未配置拦截路径,不会触发attemptAuthentication方法。
  3. 未绑定AuthenticationManager:直接new出的过滤器没有关联Spring的AuthenticationManager,即使触发也无法完成认证流程。

解决方案

步骤1:正确配置自定义过滤器

将VendorSessionAuthorizationFilter声明为Spring Bean,指定拦截路径并绑定AuthenticationManager:

@Component
public class VendorSessionAuthorizationFilter extends AbstractAuthenticationProcessingFilter {

    // 指定要拦截的端点路径,比如/vendor/**
    public VendorSessionAuthorizationFilter() {
        super(new AntPathRequestMatcher("/vendor/**"));
    }

    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        // 自定义认证逻辑示例
        String sessionToken = request.getHeader("X-Vendor-Session");
        if (sessionToken == null) {
            throw new BadCredentialsException("缺失厂商会话令牌");
        }
        VendorSessionAuthenticationToken authRequest = new VendorSessionAuthenticationToken(sessionToken);
        return getAuthenticationManager().authenticate(authRequest);
    }
}

步骤2:调整过滤器添加顺序

在configure(HttpSecurity http)中先添加自定义过滤器,再调用父类配置,确保自定义过滤器被插入到Keycloak过滤器之前:

@Autowired
private VendorSessionAuthorizationFilter vendorSessionAuthorizationFilter;
@Autowired
private VendorSessionAuthenticationProvider vendorSessionAuthenticationProvider;

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 先添加自定义过滤器和认证提供者
    http.addFilterBefore(vendorSessionAuthorizationFilter, KeycloakAuthenticationProcessingFilter.class);
    http.authenticationProvider(vendorSessionAuthenticationProvider);

    // 再执行父类的Keycloak配置
    super.configure(http);

    http
            .cors().and()
            .csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .sessionAuthenticationStrategy(sessionAuthenticationStrategy())
            .and().formLogin().disable()
            .httpBasic().disable()
            .logout().disable()
            .authorizeRequests()
            .antMatchers("/vendor/**").authenticated()
            .anyRequest().authenticated();
}

步骤3:注册自定义AuthenticationProvider

在configureGlobal方法中添加自定义认证提供者:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
    auth.authenticationProvider(keycloakAuthenticationProvider);
    // 注册自定义认证提供者
    auth.authenticationProvider(vendorSessionAuthenticationProvider);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:50:33