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 {