登錄校驗---Filter過濾器
過濾器(Filter)
- 概念: Filter 過濾器,是 JavaWeb 三大組件(Servlet、Filter、Listener)之一。
- 過濾器可以把對資源的請求攔截下來,從而實現一些特殊的功能。
- 過濾器一般完成一些通用的操作,比如: 登錄校驗、統一編碼處理、敏感字符處理等。

代碼演示
步驟
自定義Filter:繼承Filter并且重寫其方法(主要重寫doFilter())
配置Filter:配置@WebFilter(urlPatterns = ("/*"))以及攔截路徑,并且在啟動類添加注解@ServletComponentScan開啟Servlet組件支持
@WebFilter(urlPatterns = ("/*"))
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init 初始化攔截器...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("攔截到了請求...放行前");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("攔截到了請求...放行后");
}
@Override
public void destroy() {
System.out.println("destroy方法執行...");
}
}
方法介紹
init():初始化方法,Web 服務器啟動,創建Filter時調用,只調用一次
doFilter():攔截到了請求,并執行該方法,可多次調用,注意關鍵的實現filterChain.doFilter()以及攔截前后的邏輯實現
destroy():銷毀方法,服務器關閉執行,只調用一次
攔截路徑設置
| 攔截路徑 | urlPatterns值 | 含義 |
|---|---|---|
| 攔截具體路徑 | /login | 只有訪問 /login 路徑時,才會被攔截 |
| 目錄攔截 | /emps/* | 訪問/emps下的所有資源,都會被攔截 |
| 攔截所有 | /* | 訪問所有資源,都會被攔截 |
過濾器鏈
一個web應用中,可以配置多個過濾器,這多個過濾器就形成了一個過濾器鏈。
執行順序: 注解配置的Filter,優先級是按照過濾器類名(字符串A, B, C, ....)的自然排序。

擴展知識點(doFilter())
通過校驗請求認證頭(authHeader)所攜帶的token去校驗,我在Postman中使用的是Bearer Token身份校驗,Bearer Token 在請求頭中以 Bearer 關鍵字加上令牌本身的形式發送,格式通常為Authorization: Bearer <token>。詳細可看Apifox--什么是Bearer Token

代碼展示 --- doFilter()
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 設置響應頭
setupResponseHeaders(httpResponse);
// 處理預檢請求
if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
}
// 獲取請求路徑
String requestPath = httpRequest.getRequestURI();
String contextPath = httpRequest.getContextPath();
String path = requestPath.substring(contextPath.length());
// 檢查是否為排除路徑
if (isExcludePath(path)) {
chain.doFilter(request, response);
return;
}
// 獲取認證頭部
String authHeader = httpRequest.getHeader(AUTH_HEADER);
// 檢查認證頭是否存在且格式正確
if (authHeader == null || !authHeader.startsWith(BEARER_PREFIX)) {
sendUnauthorizedResponse(httpResponse, "請先登錄");
return;
}
// 提取 JWT 令牌
String jwtToken = authHeader.substring(BEARER_PREFIX.length()).trim();
try {
// 驗證 JWT 令牌
if (!JwtUtils.validateToken(jwtToken)) {
sendUnauthorizedResponse(httpResponse, "令牌無效或已過期");
return;
}
// 從 JWT 中解析用戶信息
Long userId = JwtUtils.getUserIdFromToken(jwtToken);
String userAccount = JwtUtils.getUserAccountFromToken(jwtToken);
String userName = JwtUtils.getUserNameFromToken(jwtToken);
// 將用戶信息放入請求屬性,供后續使用
httpRequest.setAttribute("id", userId);
httpRequest.setAttribute("userAccount", userAccount);
httpRequest.setAttribute("userName", userName);
System.out.println("JWT認證成功 - 用戶ID: " + userId + ", 賬號: " + userAccount);
// 繼續過濾器鏈
chain.doFilter(request, response);
} catch (Exception e) {
sendUnauthorizedResponse(httpResponse, "令牌解析失敗: " + e.getMessage());
}
}
封裝方法
在執行過濾器中,除了校驗令牌,我們還要做其他的工作
1)排除不需要認證的路徑
檢查是否為排除路徑(不需要認證的路徑):比如登錄、注冊等等
// 排除認證的路徑
private static final String[] EXCLUDE_PATHS = {
"/user/login",
"/user/register",
"/doc.html",
"/webjars/",
"/swagger-resources",
"/v2/api-docs"
};
/**
* 檢查是否為排除路徑(不需要認證的路徑)
*/
private boolean isExcludePath(String path) {
for (String excludePath : EXCLUDE_PATHS) {
if (path.startsWith(excludePath)) {
return true;
}
}
return false;
2)設置響應頭
主要處理CORS(跨域資源共享)配置和字符編碼
/**
* 設置響應頭
*/
private void setupResponseHeaders(HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With");
response.setHeader("Access-Control-Max-Age", "3600");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
}
作用:
Access-Control-Allow-Origin: "*"
- 允許所有域名訪問你的 API
- 如果是生產環境,建議改為具體域名:"
http://your-frontend.com"
Access-Control-Allow-Methods: "GET, POST, PUT, DELETE, OPTIONS"
- 允許前端使用這些 HTTP 方法
Access-Control-Allow-Headers: "Authorization, Content-Type, X-Requested-With"
- 允許前端發送這些自定義請求頭
- 特別重要:包含了 Authorization,這樣前端才能發送
JWT Token
Access-Control-Max-Age: "3600"
- 預檢請求緩存時間(1小時),減少重復的
OPTIONS請求
什么是 OPTIONS 請求
OPTIONS 是 HTTP 方法之一,用于獲取目標資源支持的通信選項。在 CORS 中,瀏覽器會自動發送 OPTIONS請求來檢查是否允許跨域訪問。
什么時候會發送 OPTIONS 請求
觸發條件:
跨域請求(域名、端口、協議不同)
非簡單請求(滿足以下任一條件):
簡單請求(不會觸發 OPTIONS):
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://frontend.com
非簡單請求(會觸發 OPTIONS):
自定義請求頭
POST /api/user HTTP/1.1
Host: localhost:8080
Origin: http://localhost:3000
Authorization: Bearer token123 # 自定義頭
X-Custom-Header: value # 自定義頭
非簡單 Content-Type
POST /api/user HTTP/1.1
Content-Type: application/json # 非簡單 Content-Type
非簡單 HTTP 方法
PUT /api/user/1 HTTP/1.1
PATCH /api/user/1 HTTP/1.1
DELETE /api/user/1 HTTP/1.1
3)發送未認證錯誤響應
/**
* 發送未認證錯誤響應
*/
private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
String jsonResponse = String.format(
"{\"code\": 401, \"message\": \"%s\", \"data\": null, \"description\": \"未授權訪問\"}",
message
);
response.getWriter().write(jsonResponse);
}
end

浙公網安備 33010602011771號