SpringBoot 2.0 不得不说的过滤器 Filter
servlet最重要的特性之一:过滤器,对访问的路径、资源进行限定拦截,实现特有的功能。比如URL级别的权限认证,session验证,Referer 过滤等等操作
现在的情况是这样的:我有一个接口,返回的是JSON数据,但如何不做限定操作,浏览器直接访问该路径的话会直接得到数据,那么用户的信息就被泄露了。
其实就这个就是http Referer防止外链的操作,不懂的也没关系,只需要知道Referer直接浏览器访问是空,Submit表单提交就会有值
好了,现在我们就来实现这个过滤的操作
User 存储用户的姓名和年龄
package priv.augus.filter.controller;
/**
* IntelliJ IDEA
*
* @author Augus
* @date 2018/8/3
*/
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
通过实现接口Filter自定义我们RefererFilter的过滤器类,这里面的逻辑就是判断Referer的值
package priv.augus.filter.controller;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* IntelliJ IDEA
*
* @author Augus
* @date 2018/8/3
*/
public class RefererFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse res = (HttpServletResponse) servletResponse;
String referer = req.getHeader("Referer");
if(referer==null){
// 为空就滚去error
res.sendRedirect("/error");
return;
}
// 有值,就继续执行下一个过滤链
filterChain.doFilter(req, res);
}
@Override
public void destroy() {
}
}
通过注解@Configuration和@Bean实现启动服务时候加载Bean
package priv.augus.filter.controller;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* IntelliJ IDEA
*
* @author Augus
* @date 2018/8/3
*/
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean refererFilterRegistration() {
FilterRegistrationBean<RefererFilter> registration = new FilterRegistrationBean<>();
//注入过滤器
registration.setFilter(new RefererFilter());
//过滤规则
registration.addUrlPatterns("/user/*");
//过滤器名称
registration.setName("ref");
//过滤器顺序
registration.setOrder(1);
return registration;
}
}
controller层就是一个简单的跳转
package priv.augus.filter.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/**
* IntelliJ IDEA
*
* @author Augus
* @date 2018/8/3
*/
@Controller
@RequestMapping("/")
public class IndexController {
@RequestMapping("/index")
public String index(){
return "index";
}
@ResponseBody
@RequestMapping("/user/all")
public List<User> getAllUser(){
// 模拟从数据库取数据返回
User user = new User("小明",23);
User user1 = new User("小大黄",12);
List<User> userList = new ArrayList<>();
userList.add(user);
userList.add(user1);
return userList;
}
}
还有个Index页面,模拟的表单提交获取数据,我这里用的thymeleaf
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form th:action="@{/user/all}" method="POST">
<input type="submit" value="获取数据">
</form>
</body>
</html>
启动服务后
浏览器访问 http://localhost:8081/user/all
通过表单 submit获取的数据
Filter 不同的实现
@Component
刚才我的实现好了,这是一个简单的测试用例
现在我们就来看看到底Filter是怎么加载的,现在大家在看我的例子,我这里面过滤的路径是/user/,如果哪里不小心配置错了,过滤的路径是/,那么恭喜你,浏览器会死循环进入/erorr页面,因为过滤器把/erorr页面也拦截了。
有人就看到网上的案例自定义的RefererFilter上面要加上@Component注解,
@Component
public class RefererFilter implements Filter {}
现在通过日志查看有什么不同
没有@Component
有@Component
我们可以知道得知原来加了@Component会自动加载一个名字叫refererFilter的过滤器,并且默认过滤路径是/*
@WebFilter注解实现
网上太多博客是说实现是这样的,可是怕是都没有去正的实现,这样是错误的
@Component
@WebFilter(urlPatterns = "/user/*", filterName = "ref")
public class RefererFilter implements Filter {
看了日志后我们发现,@WebFilter定义名字叫ref的并没有实现,反倒是@Component和之前一样默认创建了一个名字叫refererFilter的/*的过滤器
其实在springboot的启动类上加上@ServletComponentScan就可以扫描到对应的@WebFilter 并且加载了
@SpringBootApplication
@ServletComponentScan
public class FilterApplication {