Spring Boot Filter(过滤器)详解
在实际的开发过程中,可能会遇到这样一类需求:
这些需求有一个共同点——在每个接口被请求时都需要进行该类操作。换而言之,如果编写了对应以上需求的代码,在每一个接口的某处都需要对这些代码进行调用。不使用一些技巧的话,这个开发过程会变得异常烦琐。本文将介绍 Filter(过滤器)合理解决这类需求。

图1 Filter工作流程示意图
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
- 统计在线用户;
- 敏感词过滤;
- 基于URL进行访问控制。
这些需求有一个共同点——在每个接口被请求时都需要进行该类操作。换而言之,如果编写了对应以上需求的代码,在每一个接口的某处都需要对这些代码进行调用。不使用一些技巧的话,这个开发过程会变得异常烦琐。本文将介绍 Filter(过滤器)合理解决这类需求。
过滤器
Filter(过滤器)这一概念来源于“Servlet规范”,具体的功能实现由 Servlet 容器(即 Spring Boot 内容的 Tomcat)提供。过滤器的主要职责在于对资源的请求与响应的过滤,对从客户端向服务端发送的请求进行过滤,也可以对服务端返回的响应进行处理。Filter 与 Servlet 是有区别的。Filter 虽然可以对请求与响应做出处理,但其本身并不可以产生响应,如图 1 所示。
图1 Filter工作流程示意图
使用过滤器实现访问控制
(1)创建一个需要实施访问控制的控制器。在路径 src/main/java/com/example/myb-log/controller 下创建 SecretController.java:@RequestMapping("/secret") @RestController public class SecretController { @GetMapping public String secret() { //以下代码可以替换成任意需要被保护的内容 return "secret"; } }(2)创建用于身份认证的控制器。如果通过了认证,控制器将在 Cookie 中写入作为身份凭证的内容。在 controller 路径下创建 SessionController.java:
@RestController @RequestMapping("/session") public class Sessioncontroller { @PostMapping public String login(@RequestBody SessionQuery sessionQuery, HttpServletResponse response) { if (authenticate(sessionQuery)) { certifieste(response); return "success"; } //登录失败返冋错误 return "failed"; } private boolean authenticate(SessionQuery sessionQuery) { //简单的验证逻辑,仅用作演示 return Objects.equals(sessionQuery.getUsername(), "admin") && Objects.equals(sessionQuery.getPassword(), "password"); } private void certificate(HttpServletResponse response) { //将登录凭证以Cookie的形式返回给客户端 Cookie credential = new Cookie("sessionld", "test-token"); response.addCookie(credential); } }(3)创建用于检查凭证的过滤器。过滤器通过检查请求中附带的 Cookie 内容,以确认用户的身份。在路径 src/main/java/com/example/myblog/filter 下创建 SessionFilter.java:
@Slf4j @WebFilter(urlPatterns = "/secret/*") public class SessionFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //读取 Cookie Cookie[] cookies = Optional.ofNullable(((HttpServletRequest) servletRequest).getCookies()).orElse(new Cookie[0]); boolean unauthorized = true; for (Cookie cookie : cookies) { if ("sessionld".equals(cookie.getName()) && "test-token".equals(cookie.getValue())) { //验证Cookie中的凭证内容,如果通过验证则继续执行,否则返回401错误 unauthorized = false; } } if (unauthorized) { log.error("UNAUTHORIZED"); unauthorizedResp(servletResponse); } else { filterChain.doFilter(servletRequest, servletResponse); } } //向响应中写入401错误 private void unmuthorizedResp(ServletResponse response) throws IOException { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); httpResponse.setHeader("Content-type", "text/html;charset=UTF-8"); httpResponse.setCharacterEncoding("UTF-8"); httpResponse.getWriter().write("UNAUTHORIZED"); } }(4)启用过滤器。需要在主类中使用 @ServletComponentScan 注解,以启用被注解 @WebFilter 修饰的过滤器。
@SpringBootApplication @EnableConfigurationProperties({BlogProperties.class, FilestorageProperties.class}) @ServletComponentScan(basePackages = {"com.example.myblog.filter"}) public class BlogApplication { public static void main(String[] args) { SpringApplication.run(BlogApplication.class, args); } }(5)分别在请求登录接口前后访问“受保护”的路径,以确认访问控制是否生效。
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。