解决spring security自定义filter重复执行

本文讲一个spring security自定义filter非常容易出现的一个问题,那就是filter被执行两遍。

复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
复制代码@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public DemoFilter demoFilter(){
return new DemoFilter();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(demoFilter(),AnonymousAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/login","/css/**", "/js/**","/fonts/**").permitAll()
.anyRequest().authenticated();
}
}

其中DemoFilter如下

1
2
3
4
5
6
7
8
复制代码public class DemoFilter extends GenericFilterBean {

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//do something
filterChain.doFilter(servletRequest, servletResponse);
}
}

原因

在spring容器托管的GenericFilterBean的bean,都会自动加入到servlet的filter chain,而上面的定义,还额外把filter加入到了spring security的
AnonymousAuthenticationFilter之前。而spring security也是一系列的filter,在mvc的filter之前执行。因此在鉴权通过的情况下,就会先后各执行一次。

解决方案

方案1

不把filter托管给spring,直接new,比如

1
2
3
4
5
6
7
8
9
10
11
复制代码@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new DemoFilter(),AnonymousAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/login","/css/**", "/js/**","/fonts/**").permitAll()
.anyRequest().authenticated();
}
}

方案2

有时候filter需要访问spring容器的资源,托管给容器可能好些,那么这个时候,就可以像FilterSecurityInterceptor做个标记FILTER_APPLIED

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
复制代码public class DemoFilter extends GenericFilterBean {

private static final String FILTER_APPLIED = "__spring_security_demoFilter_filterApplied";

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (servletRequest.getAttribute(FILTER_APPLIED) != null) {
filterChain.doFilter(servletRequest, servletResponse);
return ;
}
//do something
servletRequest.setAttribute(FILTER_APPLIED,true);
filterChain.doFilter(servletRequest, servletResponse);
}
}

doc

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%