如何为Spring Security过滤器配置不同的AuthenticationProvider
解决Spring Security中不同过滤器绑定对应AuthenticationProvider的问题
这个问题我之前也碰到过——默认情况下Spring Security会把所有注册的AuthenticationProvider都加到全局的AuthenticationManager里,导致你的两个过滤器都会使用这个全局管理器,自然没法做到各自只用对应的Provider。下面是亲测有效的配置方案:
1. 先注册两个Provider的Bean
首先把你的两个Provider声明为Spring Bean,方便后续注入:
@Bean public AjaxAuthenticationProvider ajaxAuthenticationProvider() { return new AjaxAuthenticationProvider(); } @Bean public JwtAuthenticationProvider jwtAuthenticationProvider() { return new JwtAuthenticationProvider(); }
2. 为每个过滤器单独创建AuthenticationManager
我们需要给每个过滤器单独配置一个仅包含对应Provider的AuthenticationManager,避免全局共享:
@Bean public AuthenticationManager ajaxAuthManager(AuthenticationManagerBuilder authBuilder) throws Exception { return authBuilder .authenticationProvider(ajaxAuthenticationProvider()) // 注意不要调用parentAuthenticationManager(),避免继承全局配置 .build(); } @Bean public AuthenticationManager jwtAuthManager(AuthenticationManagerBuilder authBuilder) throws Exception { return authBuilder .authenticationProvider(jwtAuthenticationProvider()) .build(); }
3. 配置过滤器并绑定对应的AuthenticationManager
接下来创建过滤器实例,分别设置对应的AuthenticationManager和各自要处理的请求路径:
@Bean public AjaxAuthenticationFilter ajaxAuthenticationFilter() throws Exception { AjaxAuthenticationFilter filter = new AjaxAuthenticationFilter(); // 绑定专属的AuthenticationManager filter.setAuthenticationManager(ajaxAuthManager(authenticationManagerBuilder())); // 指定这个过滤器要处理的请求路径,比如Ajax登录接口 filter.setFilterProcessesUrl("/login/ajax"); return filter; } @Bean public JWTAuthenticationFilter jwtAuthenticationFilter() throws Exception { JWTAuthenticationFilter filter = new JWTAuthenticationFilter(); filter.setAuthenticationManager(jwtAuthManager(authenticationManagerBuilder())); // 指定JWT过滤器处理的路径,比如所有API请求 filter.setFilterProcessesUrl("/api/**"); return filter; }
4. 将过滤器添加到Security过滤链中
最后在WebSecurityConfig的configure(HttpSecurity http)方法里,把两个过滤器加入到合适的位置:
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() // 放行登录接口 .antMatchers("/login/ajax").permitAll() .anyRequest().authenticated() .and() // 添加Ajax过滤器,放在UsernamePasswordAuthenticationFilter之前 .addFilterBefore(ajaxAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 添加JWT过滤器,放在BasicAuthenticationFilter之前(或者你需要的位置) .addFilterBefore(jwtAuthenticationFilter(), BasicAuthenticationFilter.class); }
关键原理说明
通过为每个过滤器单独构建AuthenticationManager,我们确保了每个管理器中只包含对应的AuthenticationProvider,这样当过滤器触发认证时,只会使用绑定的Provider处理请求,不会出现混淆的情况。
内容的提问来源于stack exchange,提问作者scorpion
相关产品推荐
相关产品推荐

