SpringBoot項(xiàng)目如何設(shè)置權(quán)限攔截器和過濾器
過濾器 Filter
Servlet中的過濾器Filter是實(shí)現(xiàn)了javax.servlet.Filter接口的服務(wù)器端程序,主要的用途是設(shè)置字符集、控制權(quán)限、控制轉(zhuǎn)向、做一些業(yè)務(wù)邏輯判斷等。
其工作原理是,只要你在web.xml文件(或通過注解)配置好要攔截的客戶端請(qǐng)求,它都會(huì)幫你攔截到請(qǐng)求,此時(shí)你就可以對(duì)請(qǐng)求或響應(yīng)(Request、Response)統(tǒng)一設(shè)置編碼,簡(jiǎn)化操作;同時(shí)還可進(jìn)行邏輯判斷,如用戶是否已經(jīng)登陸、有沒有權(quán)限訪問該頁面等等工作。
作用
- 在HttpServletRequest到達(dá)Servlet之前,攔截客戶的HttpServletRequest。
- 根據(jù)需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數(shù)據(jù)。
- 在HttpServletResponse到達(dá)客戶端之前,攔截HttpServletResponse。
- 根據(jù)需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和數(shù)據(jù)。
生命周期
隨web應(yīng)用啟動(dòng)而啟動(dòng)的,只初始化一次,以后就可以攔截相關(guān)請(qǐng)求,只有當(dāng)你的web應(yīng)用停止或重新部署的時(shí)候才銷毀。
示例代碼
import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.IOException; import java.util.Base64; @Component @WebFilter(filterName = "CharestFilter" ? ? ? ? , urlPatterns = "/*" ? ? ? ? , dispatcherTypes = {DispatcherType.ASYNC, DispatcherType.ERROR} ? ? ? ? , initParams = {@WebInitParam(name = "charset", value = "utf-8")}) public class CharestFilter implements Filter { ? ? /** ? ? ?* 初始化方法 ?接收一個(gè)FilterConfig類型的參數(shù) 該參數(shù)是對(duì)Filter的一些配置 ? ? ?* ? ? ?* @param config ? ? ?* @throws ServletException ? ? ?*/ ? ? @Override ? ? public void init(FilterConfig config) throws ServletException { ? ? } ? ? /** ? ? ?* 銷毀時(shí)調(diào)用 ? ? ?*/ ? ? @Override ? ? public void destroy() { ? ? } ? ? /** ? ? ?* 過濾方法 主要是對(duì)request和response進(jìn)行一些處理,然后交給下一個(gè)過濾器或Servlet處理 ? ? ?* ? ? ?* @param request ? ? ?* @param response ? ? ?* @param chain ? ? ?* @throws ServletException ? ? ?* @throws IOException ? ? ?*/ ? ? @Override ? ? public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { ? ? ? ? HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request) { ? ? ? ? ? ? /** ? ? ? ? ? ? ?* 當(dāng)調(diào)用request.getHeader("token")時(shí),則獲取請(qǐng)求參數(shù)中token值并當(dāng)做Header的值返回 ? ? ? ? ? ? ?* @param name ? ? ? ? ? ? ?* @return ? ? ? ? ? ? ?*/ ? ? ? ? ? ? @Override ? ? ? ? ? ? public String getHeader(String name) { ? ? ? ? ? ? ? ? // 先從原本的Request中獲取頭信息,如果字段是用戶名,且值不為null時(shí),進(jìn)行解碼 ? ? ? ? ? ? ? ? String superHeader = super.getHeader(name); ? ? ? ? ? ? ? ? if ("X-USERNAME".equalsIgnoreCase(name) && StringUtils.hasText(superHeader)) { ? ? ? ? ? ? ? ? ? ? return new String(Base64.getDecoder().decode(superHeader)); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? return superHeader; ? ? ? ? ? ? } ? ? ? ? }; ? ? ? ? //交給下一個(gè)過濾器或servlet處理 ? ? ? ? chain.doFilter(requestWrapper, response); ? ? } }
攔截器 Interceptor
攔截器是在面向切面編程中應(yīng)用的,就是在service或者一個(gè)方法前調(diào)用一個(gè)方法,或者在方法后調(diào)用一個(gè)方法。是基于JAVA的反射機(jī)制。
攔截器,在AOP(Aspect-Oriented Programming)中用于在某個(gè)方法或字段被訪問之前,進(jìn)行攔截,然后在之前或之后加入某些操作。攔截是AOP的一種實(shí)現(xiàn)策略。
實(shí)現(xiàn)
第一種方式是要定義的Interceptor類要實(shí)現(xiàn)了Spring 的HandlerInterceptor 接口;
第二種方式是實(shí)現(xiàn)Spring的WebRequestInterceptor接口
或繼承這兩個(gè)接口的實(shí)現(xiàn)類子類
interceptor 的執(zhí)行順序大致為:
- 請(qǐng)求到達(dá) DispatcherServlet
- DispatcherServlet 發(fā)送至 Interceptor ,執(zhí)行 preHandle
- 請(qǐng)求達(dá)到 Controller
- 請(qǐng)求結(jié)束后,postHandle 執(zhí)行
Spring 中主要通過 HandlerInterceptor 接口來實(shí)現(xiàn)請(qǐng)求的攔截,
實(shí)現(xiàn) HandlerInterceptor 接口需要實(shí)現(xiàn)下面三個(gè)方法:
- preHandle() – 在handler執(zhí)行之前,返回 boolean 值,true 表示繼續(xù)執(zhí)行,false 為停止執(zhí)行并返回。
- postHandle() – 在handler執(zhí)行之后, 可以在返回之前對(duì)返回的結(jié)果進(jìn)行修改
- afterCompletion() – 在請(qǐng)求完全結(jié)束后調(diào)用,可以用來統(tǒng)計(jì)請(qǐng)求耗時(shí)等等
示例代碼
第一步:在pom.xml中添加依賴
<parent><!--parent 是父模塊,由父模塊統(tǒng)一進(jìn)行 spring-boot 版本管理--> ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? <artifactId>spring-boot-starter-parent</artifactId> ? ? ? ? <version>2.0.5.RELEASE</version> ? ? ? ? <relativePath/> <!-- lookup parent from repository --> ? ? </parent> <dependencies> ? ? ? ? <dependency><!--web核心依賴--> ? ? ? ? ? ? <groupId>org.springframework.boot</groupId> ? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId> ? ? ? ? </dependency> </dependencies>
第二步:新建一個(gè) intercepors 包
如圖
在 intercepors 包下的第一個(gè)java類LoginInterceptor是自定義登錄攔截器,記得在類名上加 @Component 注解,我們需要在下一步的 WebConfigurer 類中注入。
代碼如下:
import com.example.bookstore.entity.Users;//這是我自己項(xiàng)目的用戶類 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; import javax.servlet.http.HttpSession; /** ?* 登錄攔截器 ?*/ @Component public class LoginInterceptor implements HandlerInterceptor { ? ? @Override ? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ? ? ? ? //獲取請(qǐng)求的RUi:去除http:localhost:8080這部分剩下的 ? ? ? ? String uri = request.getRequestURI(); ? ? ? ? //UTL:除了login.jsp是可以公開訪問的,其他的URL都進(jìn)行攔截控制 ? ? ? ? if (uri.indexOf("login")+uri.indexOf("register") >= 0) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? //獲取session ? ? ? ? HttpSession session = request.getSession(); ? ? ? ? Users user = (Users) session.getAttribute("user"); ? ? ? ? //判斷session中是否有用戶數(shù)據(jù),如果有,則返回true,繼續(xù)向下執(zhí)行 ? ? ? ? if (user != null) { ? ? ? ? ? ? return true; ? ? ? ? } ? ? ? ? //不符合條件的給出提示信息,并轉(zhuǎn)發(fā)到登錄頁面,這里.getRequestDispatcher()的路徑換成自己項(xiàng)目的首頁路徑。parameter是一個(gè)給jsp頁面顯示的參數(shù),在jsp頁面用${parameter}就能顯示。 ? ? ? ? request.setAttribute("parameter", "您還沒有登錄,請(qǐng)先登錄!"); ? ? ? ? request.getRequestDispatcher("/WEB-INF/jsp/book/bookList.jsp").forward(request, response); ? ? ? ? return false; ? ? } ? ? @Override ? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { ? ? } ? ? @Override ? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { ? ? } }
在 intercepors 包下的第三個(gè)java類WebConfigurer是用來把自定義的攔截器告訴框架用的,需要實(shí)現(xiàn)WebMvcConfigurer 接口,并實(shí)現(xiàn)它的兩個(gè)方法。
代碼如下:
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.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfigurer implements WebMvcConfigurer { ? ? @Autowired ? ? private ?LoginInterceptor loginInterceptor; ? ? // 這個(gè)方法是用來配置靜態(tài)資源的,比如html,js,css,等等 ? ? @Override ? ? public void addResourceHandlers(ResourceHandlerRegistry registry) { ? ? } ? ? // 這個(gè)方法用來注冊(cè)攔截器,我們自己寫好的攔截器需要通過這里添加注冊(cè)才能生效 ? ? //.addPathPatterns("/**"),設(shè)置攔截的范圍,/**代表全部 ? ? // .excludePathPatterns是設(shè)置白名單,這里本項(xiàng)目中的首頁、登錄注冊(cè)、商品的瀏覽和查找是不需要判斷是否已登錄的 ? ? @Override ? ? public void addInterceptors(InterceptorRegistry registry) { ? ? ? ? registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/index","/login", "/register","/bookList","/bookName","/bookType"); ? ? } }
第三步:重新編譯部署項(xiàng)目
在IDEA中
快捷鍵 Ctrl+F9 重新部署
快捷鍵 Shift+F9重新運(yùn)行
然后在瀏覽器訪問測(cè)試即可
過濾器和攔截器的區(qū)別
Spring的Interceptor(攔截器)與Servlet的Filter有相似之處,比如二者都是AOP編程思想的體現(xiàn),都能實(shí)現(xiàn)權(quán)限檢查、日志記錄等。
不同的是:
- Filter在只在 Servlet 前后起作用。Filters 通常將 請(qǐng)求和響應(yīng)(request/response) 當(dāng)做黑盒子,F(xiàn)ilter 通常不考慮servlet 的實(shí)現(xiàn)。
- 攔截器能夠深入到方法前后、異常拋出前后等,因此攔截器的使用具有更大的彈性。允許用戶介入(hook into)請(qǐng)求的生命周期,在請(qǐng)求過程中獲取信息,Interceptor 通常和請(qǐng)求更加耦合。
- Filter 是在 Servlet 規(guī)范中定義的,是 Servlet 容器支持的。
- 而攔截器是在 Spring容器內(nèi)的,是Spring框架支持的。
總結(jié)
過濾器:所謂過濾器顧名思義是用來過濾的,在java web中,你傳入的request,response提前過濾掉一些信息,或者提前設(shè)置一些參數(shù),然后再傳入servlet或者struts的action進(jìn)行業(yè)務(wù)邏輯,比如過濾掉非法url(不是login.do的地址請(qǐng)求,如果用戶沒有登陸都過濾掉),或者在傳入servlet或者struts的action前統(tǒng)一設(shè)置字符集,或者去除掉一些非法字符(聊天室經(jīng)常用到的,一些罵人的話)。filter 流程是線性的, url傳來之后,檢查之后,可保持原來的流程繼續(xù)向下執(zhí)行,被下一個(gè)filter, servlet接收等.
java的攔截器 主要是用在插件上,擴(kuò)展件上比如 hibernate spring struts2等 有點(diǎn)類似面向切片的技術(shù),在用之前先要在配置文件即xml文件里聲明一段的那個(gè)東西。
在Spring構(gòu)架的程序中,要優(yōu)先使用攔截器。幾乎所有 Filter 能夠做的事情, interceptor 都能夠輕松的實(shí)現(xiàn)
最后
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot配置多數(shù)據(jù)源的實(shí)例(MongoDB主從)
下面小編就為大家分享一篇springboot配置多數(shù)據(jù)源的實(shí)例(MongoDB主從),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12基于MybatisPlus插件TenantLineInnerInterceptor實(shí)現(xiàn)多租戶功能
這篇文章主要介紹了基于MybatisPlus插件TenantLineInnerInterceptor實(shí)現(xiàn)多租戶功能,需要的朋友可以參考下2021-11-11詳解使用Spring快速創(chuàng)建web應(yīng)用的兩種方式
這篇文章主要介紹了詳解使用Spring快速創(chuàng)建web應(yīng)用的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11關(guān)于Spring啟動(dòng)流程及Bean生命周期梳理
這篇文章主要介紹了關(guān)于Spring啟動(dòng)流程及Bean生命周期梳理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11純Java實(shí)現(xiàn)數(shù)字證書生成簽名的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)硪黄僇ava實(shí)現(xiàn)數(shù)字證書生成簽名的簡(jiǎn)單實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-08-08