您好,登錄后才能下訂單哦!
本文介紹了SpringBoot使用自定義注解實現權限攔截的示例,分享給大家,具體如下:
HandlerInterceptor(處理器攔截器)
常見使用場景
使用自定義注解實現權限攔截
首先HandlerInterceptor了解
在HandlerInterceptor中有三個方法:
public interface HandlerInterceptor { // 在執行目標方法之前執行 boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)throws Exception; // 執行目標方法之后執行 void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception; // 在請求已經返回之后執行 void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception; }
在以上注釋中已經寫明執行順序, 測試及測試結果如下:
public class TestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandler"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandler"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
結果:
preHandler
postHandler
afterCompletion
如何配置攔截器后面講:
下面來講講這個攔截器是攔截的什么?
方法攔截器HandlerInterceptor
我們使用SpringMVC都知道SpringMVC是基于方法的請求處理, 和Struts2有明顯區別(我是這么理解的), 并且Controller是單例模式, 所有請求都是從DispatcherServlet來調用請求url對應的方法的(處理器映射器的功能), 那么它是一個方法攔截器, 如何知道呢?
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println(handler.getClass()); return true; }
執行結果:
class org.springframework.web.method.HandlerMethod
已經看到攔截器如何工作, 并且知道它是方法級別的攔截器, 那么接下來看看如何配置攔截器, 讓它在服務器運行期間起作用
實現HandlerInterceptor
實現HandlerInterceptor接口或者繼承HandlerInterceptorAdapter類
HandlerInterceptorAdapter適配器是對HandlerInterceptor接口做了默認實現, 這種適配器模式, 是為了方便開發者只去想要復寫方法, 其他方法采取默認措施.
上面的TestInterceptor就是一個Demo, 具體可以按需求在我們想要攔截的位置進行相應的邏輯處理
配置攔截器
從Spring4.x開始, 就支持注解配置具體是使用@Configuration注解標注一個普通類, 使該類成為配置類, 可以在該類中定義Bean, 以及注入一些配置參數等.
首先, 我們要配置攔截器,就需要想SpringMvc的攔截鏈中取注入我們的攔截器, 這樣才能請求進來時去攔截我們想要攔截的請求, 所以, 需要我們新建一個普通類, 使用@Configuration注解標注在類名上, 并且讓該類繼承WebMvcConfigurerAdapter,為什么不實現WebMvcConfigurer接口呢? 因為方法太多,我們不需要復寫其中所有方法...
下面讓我們新建一個配置類, 來配置我們的攔截器
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**"); } }
復寫addInterceptors之后, 當我們的服務器啟動時, 會自動調用這個方法, 參數怎么傳我們都不用管(目前是java初級階段, 沒空研究Spring深層原理), 我們只要知道這個方法一定會被調用就行了.
我們直接new一個自定義攔截器, 注冊到整個攔截鏈中, 并且制定攔截路徑, 這樣當滿足請求url攔截配置時, 我們的自定義攔截器就會執行相應的方法了.
攔截方法是非常靈的, 除了攔截配置的, 也可以攔截非匹配的, 也可以根據正則表達式攔截請求
至此, 我們的攔截器就完成了, 接下來自定義權限相關注解
自定義權限注解
定義一個@interface類
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Access { String[] value() default {}; String[] authorities() default {}; String[] roles() default {}; }
@Target注解是標注這個類它可以標注的位置:
常用的元素類型(ElementType):
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ // TYPE類型可以聲明在類上或枚舉上或者是注解上 TYPE, /** Field declaration (includes enum constants) */ // FIELD聲明在字段上 FIELD, /** Method declaration */ // 聲明在方法上 METHOD, /** Formal parameter declaration */ // 聲明在形參列表中 PARAMETER, /** Constructor declaration */ // 聲明在構造方法上 CONSTRUCTOR, /** Local variable declaration */ // 聲明在局部變量上 LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE }
@Retention注解表示的是本注解(標注這個注解的注解保留時期)
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ // 源代碼時期 SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ // 字節碼時期, 編譯之后 CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ // 運行時期, 也就是一直保留, 通常也都用這個 RUNTIME }
@Documented是否生成文檔的標注, 也就是生成接口文檔是, 是否生成注解文檔
注解說完了, 下面需要到對應的controller的方法中取添加注解, 配置該方法允許的權限
在方法上配置權限
@RestController public class HelloController { @RequestMapping(value = "/admin", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET) // 配置注解權限, 允許身份為admin, 或者說允許權限為admin的人訪問 @Access(authorities = {"admin"}) public String hello() { return "Hello, admin"; } }
編寫權限邏輯
// 自定義一個權限攔截器, 繼承HandlerInterceptorAdapter類 public class AuthenticationInterceptor extends HandlerInterceptorAdapter { // 在調用方法之前執行攔截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 將handler強轉為HandlerMethod, 前面已經證實這個handler就是HandlerMethod HandlerMethod handlerMethod = (HandlerMethod) handler; // 從方法處理器中獲取出要調用的方法 Method method = handlerMethod.getMethod(); // 獲取出方法上的Access注解 Access access = method.getAnnotation(Access.class); if (access == null) { // 如果注解為null, 說明不需要攔截, 直接放過 return true; } if (access.authorities().length > 0) { // 如果權限配置不為空, 則取出配置值 String[] authorities = access.authorities(); Set<String> authSet = new HashSet<>(); for (String authority : authorities) { // 將權限加入一個set集合中 authSet.add(authority); } // 這里我為了方便是直接參數傳入權限, 在實際操作中應該是從參數中獲取用戶Id // 到數據庫權限表中查詢用戶擁有的權限集合, 與set集合中的權限進行對比完成權限校驗 String role = request.getParameter("role"); if (StringUtils.isNotBlank(role)) { if (authSet.contains(role)) { // 校驗通過返回true, 否則攔截請求 return true; } } } // 攔截之后應該返回公共結果, 這里沒做處理 return false; } }
至此, 我們啟動服務器, 訪問接口, 就能看到效果, 這里不做示范了
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。