攔截器的使用

攔截器(Interceptor)是一種在應用程序中用于干預、修改或攔截請求和響應的組件,是AOP 編程的一種實踐,和過濾器一樣都是一種具體的AOP實現。它可以在請求被發送到目標處理程序之前或之后,對請求進行預處理或對響應進行后處理。

攔截器通常用于以下目的:

  1. 認證和授權:攔截器可以對請求進行身份驗證和權限檢查,確保只有經過認證和授權的用戶才能訪問特定的資源或執行特定的操作。

  2. 日志記錄和性能監控:攔截器可以用于記錄請求和響應的日志,以便進行故障排查、性能監控和分析。

  3. 請求轉發和重定向:攔截器可以根據特定的條件,對請求進行轉發或重定向至不同的處理程序或頁面。

  4. 數據轉換和格式化:攔截器可以對請求和響應的數據進行轉換、格式化或驗證,以滿足特定的需求或規范。

在很多框架和應用程序中都有攔截器的概念,比如在Java中的Spring MVC框架中,可以使用攔截器來攔截和處理HTTP請求;在網絡安全領域,防火墻和入侵檢測系統也可以使用攔截器來攔截和過濾惡意流量。攔截器在應用程序中起到了很重要的作用,增強了系統的安全性、可靠性和可控性。

1.攔截器的編寫方法?

攔截器的編寫比較簡單,一般是根據自己的不同需要繼承不同的攔截器基類。大致分為兩類,一類是基于業務判斷服務的攔截器,比如:日志服務,權限認證,這種攔截器一般繼承自?HandlerInterceptor類;另一類是和配置有關的攔截器,一般繼承自?WebMvcConfigurer 。其中第一類最多,需要重寫 preHandle 和 postHandle 方法,其中 preHandle 方式用于請求執行前的時候,當preHandle 返回? true 才能進行下一個方法,而 postHandle 是作用于請求結束前。afterCompletion 是視圖顯示完成后才會執行。?

第一類,基于 HandlerNterceptor 類的攔截器 ,用于日志服務:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;@Component
public class LoggerInterceptor extends HandlerInterceptorAdapter {//生成日志類private Logger logger = LoggerFactory.getLogger(LoggerInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HandlerMethod handlerMethod = (HandlerMethod) handler;// Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.Method method = handlerMethod.getMethod();//得到方法信息//從當前方法中獲取一個日志注解對象LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);if (logAnnotation != null){long startTime = System.currentTimeMillis();request.setAttribute("startTime",startTime);//設置屬性logger.info("enter"+method.getName()+"method cost time is:"+startTime+" ms");}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();//得到方法信息LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);if (logAnnotation != null){long endTime = System.currentTimeMillis();long startTime = (long) request.getAttribute("startTime");long periodTime = endTime- startTime;logger.info("Leave "+method.getName()+"method time is:"+endTime+" ms");logger.info("On "+method.getName()+"method cost time is:"+periodTime+" ms");}}
}

將分別計算并輸出進入某個方法和離開某個方法的時間。?

聲明注解 :在需要使用該服務的方法上加上該注解即可使用

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface LogAnnotation {String message() default "666";String[] params() default {};}

注冊配置攔截器:實現WebMvcConfigurer接口,并重寫addInterceptors方法

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoggerInterceptor loggerInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loggerInterceptor).addPathPatterns("/**").excludePathPatterns("/ls");//不攔截的路徑}
}

2.郵箱有效性驗證?

常見的郵箱如 qq,網易,地址形式如 xxx@qq.com ,xxx@163.com?.

總結成正則表達式如下:

"^([a-z0-9A-z]+[-|\\.]?)+[a-z0-9A-z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+([a-zA-Z]{2,})$"

用Java編寫一個檢查有效性的例子:

 public static boolean matchTest(String email){boolean a = email.matches("^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+([a-zA-Z]{2,})$");System.out.println(a);return a;}

編寫完整的攔截器:

import org.example.service.Testjson;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class EmailInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String email = request.getParameter("email");if (Testjson.matchTest(email)){return true;}else {return false;}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

這里只需要重寫 preHandle 方法即可,完成對有效性郵箱地址的判斷效果。

3.Token 檢查攔截器實現

Token檢查是一個健全系統或者服務必須有的一項安全性功能,特別是基于 RESTful 的接口,需要檢查Token來判斷用戶是否已經登陸或者驗證身份,利用Token可以獲取進一步的網絡資源和權限。

一般我們會使用 JWT 驗證方式,JSON Web Token 簡稱 JWT。本質上是一段字符串,由以下三個部分構成。

  • 頭部: JWT 基本信息,包括算法。
  • 荷載: 自定義數據,包括用戶標識,如 userid。
  • 簽名: 前面兩者通過一定加密算法后計算所得其簽名字符串。

引入 JWT 依賴到 pom.xml 文件中,代碼如下:

        <dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency>

更新前端攔截器配置,處理所有請求:

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate LoggerInterceptor loggerInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loggerInterceptor).addPathPatterns("/**").excludePathPatterns("/ls");//不攔截的路徑registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**");}@Beanpublic AuthenticationInterceptor authenticationInterceptor(){return new AuthenticationInterceptor();}
}

新建兩個注解,用于判斷是否進行Token驗證,首先編寫需要登陸驗證的注解UserLoginToken:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 需要登陸才能操作得注解*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {boolean required() default true;
}

用于跳過驗證的注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {boolean required() default true;
}

檢查Token的攔截器:

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import org.example.Exception.BusinessException;
import org.example.pojo.User;
import org.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;@Component
public class AuthenticationInterceptor implements HandlerInterceptor {@AutowiredUserService userService;@AutowiredRedisUtil redisUtil;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");//排除訪問的是靜態資源,而不是映射訪問if (!(handler instanceof HandlerMethod)){return true;}//獲取訪問的方法HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();//是否被跳過驗證注解if (method.isAnnotationPresent(PassToken.class)){PassToken passToken = method.getAnnotation(PassToken.class);if (passToken.required()){return true;}}if (method.isAnnotationPresent(UserLoginToken.class)){UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);if (userLoginToken.required()){if (token == null){throw new BusinessException("4001","no token");}String userId;try{userId = JWT.decode(token).getAudience().get(0);}catch (Exception e){throw new BusinessException("4003","decode token fails");}//Check the expire of tokenString tokenKey = userId+":"+token;boolean hasExisted = redisUtil.hasKey(tokenKey);System.out.println("exit or not: "+hasExisted);if (!hasExisted){throw new BusinessException("4005","token expired!");}int userID = Integer.parseInt(userId);System.out.println("userId is:"+userID);User user =userService.findUserById(userID);if (user == null){throw new RuntimeException("user not exits");}try {JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword()+"MTest!76&sQ^")).build();jwtVerifier.verify(token);//設置當前登錄用戶LoginUser loginUser = new LoginUser();loginUser.setID((long)userID);UserContext.setUser(loginUser);}catch (JWTVerificationException e){throw new BusinessException("4002","invalid token");}}}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

使用起來也很方便,在需要與不需要進行 Token 驗證的接口前面加上對應的注釋即可。

補充:

?handler?參數是 Spring MVC 框架傳遞給你的?preHandle?方法的一個對象,它代表當前請求即將要調用的控制器邏輯。在 Spring MVC 中,這個?handler?對象可以是多種類型,但通常它是?HandlerMethod?的一個實例

當一個請求被映射到某個控制器的方法時,這個方法就被包裝為?HandlerMethod?對象。HandlerMethod?對象包含了這個方法以及包含這個方法的控制器的信息,允許你在攔截器中對即將執行的控制器方法進行一些前處理。

在某些情況下,handler?可能不是?HandlerMethod?的實例。例如,當請求是針對靜態資源時,或者是某個請求沒有被映射到任何的控制器上的方法時handler?可能是框架中其他類型的處理器,這取決于你的應用配置和請求的具體類型。這就是為什么在?preHandle?方法中進行?instanceof HandlerMethod?檢查是一種常見的做法,以確保你正在處理的是一個具體的控制器方法。如果是,則可以安全地轉型到?HandlerMethod?并進行進一步的處理。

在?preHandle?方法的上下文中,你可以對?handler?參數進行各種檢查和操作。例如,你可以檢查用戶是否有權限執行與?handler?對應的控制器方法,你可以修改請求或響應,或者決定是否繼續執行請求處理鏈(通過返回?true?或者?false)。

在Spring MVC框架中:

靜態資源請求:
? 這些請求通常不需要經過復雜的處理,它們被映射到服務器上存儲靜態文件的目錄。例如在Spring Boot中,靜態資源可以放置在 `/static`、`/public` 等默認的資源目錄中,這些目錄中的資源可以直接通過URL被訪問。在這種情況下,與靜態資源對應的`handler`可能就不是一個`HandlerMethod`,而是其他用于處理靜態資源的類的實例。

數據請求:
? 這些請求需要后端處理,如執行數據庫操作、進行計算或調用其他接口等。在Spring MVC中,這些請求被映射到控制器類中的特定方法上,這些方法通過注解(如`@RequestMapping`或其特化版本比如`@GetMapping`、`@PostMapping`等)來標注。這時候傳遞給`preHandle`方法的`handler`參數就是一個`HandlerMethod`實例,代表被映射的那個方法。

因此,在攔截器的`preHandle`方法中,進行`handler instanceof HandlerMethod`檢查可以幫助你明確該次請求是需要Spring MVC通過控制器中的方法處理,還是僅僅是為了獲取靜態資源。這可以確保你的攔截器邏輯只應用于實際需要攔截的后端處理請求,而不是靜態資源請求。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165654.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165654.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165654.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【數據結構】二叉樹概念 | 滿二叉樹 | 完全二叉樹

二叉樹的概念 二叉樹在實踐中用的很多。 一棵二叉樹是結點的一個有限集合&#xff0c;該集合&#xff1a; 或者為空&#xff1b;由一個根結點加上兩棵別稱為左子樹和右子樹的二叉樹組成。二叉樹最多兩個孩子。 這里注意&#xff1a;二叉樹并不是度為2的樹。 二叉樹的度最大值是…

Go lumberjack 日志輪換和管理

在開發應用程序時&#xff0c;記錄日志是一項關鍵的任務&#xff0c;以便在應用程序運行時追蹤問題、監視性能和保留審計記錄。Go 語言提供了靈活且強大的日志記錄功能&#xff0c;可以通過多種方式配置和使用。其中一個常用的日志記錄庫是 github.com/natefinch/lumberjack&am…

python selenium 模擬瀏覽器自動操作搶購腳本

每逢秒殺&#xff0c;都在遺憾網速和手速慢沒能搶購到商品吧。 手寫一個腳本&#xff0c;讓程序幫你搶&#xff0c;搶到的概率會大大提升。 廢話不多說&#xff0c;直接上代碼。 本實例以華為官網搶購手機為例 """ 模擬瀏覽器操作華為官網(1) 【只需要安裝一…

【JAVA】我們該如何規避代碼中可能出現的錯誤?(二)

個人主頁&#xff1a;【&#x1f60a;個人主頁】 系列專欄&#xff1a;【??初識JAVA】 文章目錄 前言異常方法&#xff08;Throwable類&#xff09;Throwable類的方法 捕獲異常多重捕獲塊 前言 異常是程序中的一些錯誤&#xff0c;但并不是所有的錯誤都是異常&#xff0c;并…

git-3

1.如何讓工作區的文件恢復為和暫存區一樣&#xff1f; 工作區所作的變更還不及暫存區的變更好&#xff0c;想從暫存區拷貝到工作區&#xff0c;變更工作區(恢復成和暫存區一樣的狀態)&#xff0c;想到用git checkout -- 文件名 2.怎樣取消暫存區部分文件的更改&#xff1f; 如…

無損壓縮技巧:減小PDF文件尺寸的有效方法

我們在制作pdf文檔的時候&#xff0c;會加入許多內容&#xff0c;文字、圖片等等&#xff0c;素材添加的過多之后就會導致pdf文檔特別大&#xff0c;在上傳或者儲存時&#xff0c;就會特別不方便&#xff0c;所以今天就告訴大家一個pdf壓縮的方法&#xff0c;使用pdf在線壓縮工…

4-Docker命令之docker info

后續為大家逐個講解一下docker常用命令及其相關用法。docker常用命令查看如下: [root@centos79 ~]# docker --helpUsage: docker [OPTIONS] COMMANDA self-sufficient runtime for containersCommon Commands:run Create and run a new container from an imageexec…

洛谷 P1883 函數

P1883 函數 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) Error Curves - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) 這兩題是一模一樣的&#xff0c;過一題水兩題。 分析 主要難點在于證明F(x)是一個單峰函數可以被三分&#xff0c;但是我隨便畫了幾個f(x)之后發現好像…

MySQL的Redo Log跟Binlog

文章目錄 概要Redo Log日志Redo Log的作用Redo Log的寫入機制 Binlog日志Binlog的作用Binlog寫入機制 兩段提交 概要 Redo Log和Binlog是MySQL日志系統中非常重要的兩種機制&#xff0c;也有很多相似之處&#xff0c;本文主要介紹兩者細節和區別。 Redo Log日志 Redo Log的作…

Docker+ Jenkins+Maven+git自動化部署

環境&#xff1a;Centos7 JDK1.8 Maven3.3.9 Git 2.40 Docker 20.10.17 準備工作&#xff1a; 安裝Docker Centos7默認的yum安裝的docker是1.13&#xff0c;版本太低&#xff0c;很多鏡像都要Docker版本要求&#xff0c;升級Docker版本。 卸載已安裝Docker: yum …

你知道如何實現游戲中的透視效果嗎?

引言 游戲中的透視效果可以合理運用CtrlCV實現。 不知道大家有沒有這樣一段經歷&#xff1a;在做Cocos項目時需要一些特定的Shader去做一些特定的效果&#xff0c;例如透視、高光、濾鏡等等&#xff0c;想自己寫吧&#xff0c;不怎么會啊&#xff0c;網上又找不到&#xff0c…

27 - 如何使用設計模式優化并發編程?

在我們使用多線程編程時&#xff0c;很多時候需要根據業務場景設計一套業務功能。其實&#xff0c;在多線程編程中&#xff0c;本身就存在很多成熟的功能設計模式&#xff0c;學好它們&#xff0c;用好它們&#xff0c;那就是如虎添翼了。今天我就帶你了解幾種并發編程中常用的…

redis-cluster集群(目的:高可用)

1、特點 集群由多個node節點組成&#xff0c;redis數據分布在這些節點中&#xff0c;在集群中分為主節點和從節點&#xff0c;一個主對應一個從&#xff0c;所有組的主從形成一個集群&#xff0c;每組的數據是獨立的&#xff0c;并且集群自帶哨兵模式 2、工作原理 集群模式中…

【ZedBoard學習實例1】 VGA顯示彩條

ZedBoard學習實例1 VGA顯示彩條 ZedBoard學習實例1 VGA顯示彩條參考文章改進 ZedBoard學習實例1 VGA顯示彩條 參考文章 彩條控制verilog代碼 主體參考了該文章的代碼&#xff0c;文中還介紹了相關的電路圖&#xff0c;還有ZedBoard的手冊內容。19201080分辨率顯示器的參數 針…

重生之我是一名程序員 37 ——C語言中的棧溢出問題

哈嘍啊大家晚上好&#xff01; 今天呢給大家帶來一個燒腦的知識——C語言中的棧溢出問題。那什么是棧溢出呢&#xff1f;棧溢出指的是當程序在執行函數調用時&#xff0c;為了保護函數的局部變量和返回地址&#xff0c;將這些數據存儲在棧中。如果函數在函數調用時使用了過多的…

Sentinel核心類解讀:Entry

默認情況下&#xff0c;Sentinel會將controller中的方法作為被保護資源&#xff0c;Sentinel中的資源用Entry來表示。 Sentinel中Entry可以理解為每次進入資源的一個憑證&#xff0c;如果調用SphO.entry()或者SphU.entry()能獲取Entry對象&#xff0c;代表獲取了憑證&#xff…

安卓手機便簽APP用哪個,手機上好用的便簽APP是什么

在日常生活及工作方面&#xff0c;總是有許多做不完的事情需要大家來處理&#xff0c;當多項任務堆疊交叉在一起時&#xff0c;很容易漏掉一些項目&#xff0c;這時候大家會借助經常攜帶的手機來記錄容易忘記的事情&#xff0c;如手機上的鬧鐘、定時提醒軟件都可以用來記錄待辦…

2023亞太杯數學建模A題思路分析 - 采果機器人的圖像識別技術

1 賽題 問題A 采果機器人的圖像識別技術 中國是世界上最大的蘋果生產國&#xff0c;年產量約為3500萬噸。與此同時&#xff0c;中國也是世 界上最大的蘋果出口國&#xff0c;全球每兩個蘋果中就有一個&#xff0c;全球超過六分之一的蘋果出口 自中國。中國提出了一帶一路倡議…

JDK11新特性

目錄 一、JShell 二、Dynamic Class-File Constants類文件新添的一種結構 三、局部變量類型推斷&#xff08;var ”關鍵字”&#xff09; 四、新加的一些實用API 1. 新的本機不可修改集合API 2. Stream 加強 3. String 加強 4. Optional 加強 5. 改進的文件API 五、移…

canvas

Canvas 是 Android 中用于繪制圖形的重要類&#xff0c;它提供了許多用于繪制的常用方法。以下是一些常用的 Canvas 方法&#xff1a; 繪制顏色和背景&#xff1a; drawColor(int color): 用指定顏色填充整個畫布。drawRGB(int r, int g, int b): 用 RGB 值指定顏色填充整個畫布…