过滤器可以简单理解成用于拦截请求,并执行相应逻辑的代码。
在SpringSecurity中,可以通过实现 javax.servlet 包中的 Filter接口构造过滤器。
我们通过实现Filter 接口的doFilter() 方法,执行相关逻辑。该方法包含三个参数:
Spring Security为我们提供了一些过滤器实现,例如:
多个过滤器集合在一起形成一条过滤链,它们之间有一定顺序。你可以通过存在于过滤链上的一个过滤器,在它的相对位置添加一个新的过滤器。
可以通过下面的方法在某过滤器前面添加一个新的过滤器。
@Configuration public class ProjectConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(new CustomFilter(), BasicAuthenticationFilter.class); } }
CustomFilter是你自定义实现的过滤器类,BasicAuthenticationFilter是认证过滤器的默认类型。
下面的代码是在某过滤器后面添加一个新的过滤器。
@Configuration public class ProjectConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); } }
下面代码是在一个过滤器的位置上,添加一个新的过滤器。
@Configuration public class ProjectConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http..addFilterAt(new CustomFilter(), BasicAuthenticationFilter.class); } }
当在一个过滤器的位置上,加入一个新的过滤器,Spring Security不会假设该位置上只有一个过滤器, 它也不会保证该位置上过滤器的顺序。
Spring Security 提供了一些实现Filter借口的抽象类,并在里面加入一些功能。你可以通过继承这些类来构建过滤器类。例如OncePerRequestFilter等。由于Spring Security不能保证一个过滤器对于同一个请求不会被调用多次,我们可以是过滤器继承OncePerRequestFilter来保证。
在过滤器BasicAuthenticationFilter的前面、当前位置、后面各添加一个新的过滤器。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class BeforeFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("BeforeFilter: " + "在其前面插入的过滤器"); chain.doFilter(request, response); } }
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class CurrentFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("CurrentFilter: " + "在其当前位置插入的过滤器"); chain.doFilter(request, response); } }
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class AfterFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("AfterFilter: " + "在其后面插入的过滤器"); chain.doFilter(request, response); } }
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import hookind.security009.filter.AfterFilter; import hookind.security009.filter.BeforeFilter; import hookind.security009.filter.CurrentFilter; @Configuration public class ProjectConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().permitAll(); // 在前面加入一个过滤器 http.addFilterBefore(new BeforeFilter(), BasicAuthenticationFilter.class); // 在当前位置加入一个过滤器 http.addFilterAt(new CurrentFilter(), BasicAuthenticationFilter.class); // 在其后面加入一个过滤器 http.addFilterAfter(new AfterFilter(), BasicAuthenticationFilter.class); } }
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "Hello"; } }
启动程序后,在浏览器输入网址 http://localhost:8080/hello
,我的控制台输出如下:
BeforeFilter: 在其前面插入的过滤器 CurrentFilter: 在其当前位置插入的过滤器 AfterFilter: 在其后面插入的过滤器 BeforeFilter: 在其前面插入的过滤器 CurrentFilter: 在其当前位置插入的过滤器 AfterFilter: 在其后面插入的过滤器 BeforeFilter: 在其前面插入的过滤器 CurrentFilter: 在其当前位置插入的过滤器 AfterFilter: 在其后面插入的过滤器
由上可知,过滤器是按BeforeFilter、CurrentFilter、AfterFilter顺序调用的。也表示,对于同一个请求,Spring Security可能会调用同一个过滤器多次。