SpringBoot快速設置攔截器并實現(xiàn)權(quán)限驗證的方法
一、概述
攔截器的使用場景越來越多,尤其是面向切片編程流行之后。那通常攔截器可以做什么呢?
之前我們在Agent介紹中,提到過統(tǒng)計函數(shù)的調(diào)用耗時。這個思路其實和AOP的環(huán)繞增強如出一轍。
那一般來說,場景如下:
- 函數(shù)增強:比如對一個函數(shù)進行參數(shù)檢查,或者結(jié)果過濾等。甚至可以對函數(shù)就行權(quán)限認證。
- 性能監(jiān)控:統(tǒng)計函數(shù)性能。
- 日志打點:比如在用戶登錄函數(shù)之前,打點統(tǒng)計PV等信息。
以及其他等等。
二、Spring的攔截器
無論是SpringMVC或者SpringBoot中,關(guān)于攔截器不得不提:
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor { // 在目標方法執(zhí)行前執(zhí)行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } // 在目標方法執(zhí)行后執(zhí)行,但在請求返回前,我們?nèi)匀豢梢詫?ModelAndView進行修改 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {} // 在請求已經(jīng)返回之后執(zhí)行 @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {} // 用來處理異步請求, 當Controller中有異步請求方法的時候會觸發(fā)該方法 @Override public void afterConcurrentHandlingStarted( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {} }
三、實現(xiàn)一個用于驗證簡單權(quán)限的攔截器
1、自定義一個權(quán)限注解 @Auth
@Inherited @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Auth { String user() default ""; }
- @Inherited:在使用此自定義注解時,如果注解在類上面時,子類會自動繼承此注解,否則,子類不會繼承此注解。這里一定要記住,使用Inherited聲明出來的注解,只有在類上使用時才會有效,對方法,屬性等其他無效。
- @Target:表示此注解可以放置的位置。常見的位置有:TYPE=枚舉或注解上,F(xiàn)IELD=字段上,METHOD=方法上,PARAMETER=函數(shù)形參列表中,CONSTRUCTOR=構(gòu)造函數(shù)上,LOCAL_VARIABLE=局部變量上 等等其他位置。
- @Retention:此注解的生命周期。常見的有:SOURCE=源碼時期;CLASS=字節(jié)碼時期(已編譯);RUNTIME=運行時期,通常是用這個的時候要多。
- @Documentd:生成注解文檔。
2、在Controller的方法上添加注解
上一步添加完注解后,之后要在你所使用的方法上添加相關(guān)注解,如下。
@RestController @EnableAutoConfiguration public class DemoController { @Auth(user = "admin") @RequestMapping(value = "/hello", method = RequestMethod.GET) public String sayHello() { return "hello world."; } }
3、實現(xiàn)攔截器功能
需求:我們在用戶通過/hello這個URI訪問時,對其進行驗證,如果為admin則放行,否則拒絕,假設用戶的身份在URL參數(shù)中。
思路:因此我們要在執(zhí)行sayHello()之前,對用戶做出驗證。如果其身份與注解中的身份相同,則放行。因此我們要在preHandle()中做文章。
難點:我們怎么拿到Controller 方法上的@Auth這個注解呢?看PreHandle()的三個參數(shù),貌似也沒有哪個可以提供Controller類中的注解。
其實,第三個參數(shù)handler,一般情況下其類型為:org.springframework.web.method.HandlerMethod類型,而這里面含有注解的相關(guān)信息。
為什么這么說呢?
在SpringBoot中,注解的默認類型為函數(shù)級,而在SpringMVC其默認類型為Controller對象級別。
因此,如果在SpringMVC中需要在dispatcher-servlet.xml中配置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>,這樣其類型才為HandlerMethod。
我們看下具體實現(xiàn)邏輯:
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) { System.out.println("cat cast handler to HandlerMethod.class"); return true; } // 獲取注解 Auth auth = ((HandlerMethod) handler).getMethod().getAnnotation(Auth.class); if (auth == null) { System.out.println("cant find @Auth in this uri:" + request.getRequestURI()); return true; } // 從參數(shù)中取出用戶身份并驗證 String admin = auth.user(); if (!admin.equals(request.getParameter("user"))) { System.out.println("permission denied"); response.setStatus(403); return false; } return true; }
其實實現(xiàn)邏輯就兩點:從參數(shù)中取出身份,和注解中的進行比對。
4、配置攔截器
那怎么讓剛才的這個攔截器生效呢?
這個時候,需要我們配置:WebMvcConfigurerAdapter
具體實現(xiàn)如下:
@Configuration public class ConfigAdapter extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/hello"); } }
注意:這里有兩點需要注意,一個是@Configuration這個注解,這樣才能讓SpringBoot服務發(fā)現(xiàn)這個配置;另一個是配置匹配項,這里是對"/hello"這個進行攔截。("/**"是對所有的訪問攔截)
四、運行
訪問 http://127.0.0.1:8080/hello?user=admin就可以看到結(jié)果啦。
本文中的代碼詳見:https://github.com/hawkingfoo/springboot-interceptor
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot校園綜合管理系統(tǒng)實現(xiàn)流程分步講解
這篇文章主要介紹了SpringBoot+Vue實現(xiàn)校園綜合管理系統(tǒng)流程分步講解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-09-09Spring Cloud Alibaba和Dubbo融合實現(xiàn)
這篇文章主要介紹了Spring Cloud Alibaba和Dubbo融合實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-04-04利用Java實現(xiàn)word導入導出富文本(含圖片)的詳細代碼
這篇文章主要為大家詳細介紹了利用Java實現(xiàn)word導入導出富文本(含圖片),文中的示例代碼講解詳細,對大家的學習或工作有一定的幫助,感興趣的小伙伴可以學習一下2024-02-02Java調(diào)用opencv實現(xiàn)圖片矯正功能
這篇文章主要為大家詳細介紹了Java如何調(diào)用opencv實現(xiàn)圖片矯正功能,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學習一下2023-09-09Java?使用geotools讀取tiff數(shù)據(jù)的示例代碼
這篇文章主要介紹了Java?通過geotools讀取tiff,一般對于tiff數(shù)據(jù)的讀取,都會借助于gdal,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下2022-04-04JAVA實現(xiàn)基于Tcp協(xié)議的簡單Socket通信實例
本篇文章主要介紹了JAVA實現(xiàn)基于Tcp協(xié)議的簡單Socket通信實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01