妙用“SpringBoot”攔截器,讓你一個(gè)人開(kāi)發(fā)整個(gè)系統(tǒng)的鑒權(quán)模塊!

推薦學(xué)習(xí):4步肝爆SpringBoot,基礎(chǔ)入門→ 核心原理→底層源碼→突擊面試!

image

HandlerInterceptor 詳解

HandlerInterceptor 允許定制 handler 處理器執(zhí)行鏈的工作流接口。我們可以自定義攔截器用于攔截 handlers 處理器(你可以理解為 controller 層的接口),從而可以添加一些共同的重復(fù)性的處理行為(例如接口鑒權(quán),接口日志記錄,性能監(jiān)控等),而不用修改每一個(gè) handler 的實(shí)現(xiàn)。

注意,此基于 SpringBoot 2.3.12.RELEASE 版本講解。

HandlerInterceptor 接口只有三個(gè)默認(rèn)空實(shí)現(xiàn)方法,在低版本中這三個(gè)方法不是默認(rèn)方法,而是抽象方法。

public interface HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response,                 Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response,             Object handler, @Nullable Exception ex) throws Exception {
    }
}

這三個(gè)方法的執(zhí)行順序圖如下:

image

preHandle

preHandle 前置處理,攔截一個(gè)處理器(handler)的執(zhí)行,preHandle 方法會(huì)在 HandlerMapping 確定一個(gè)適當(dāng)?shù)奶幚砥鲗?duì)象之后,但在 HandlerAdapter 調(diào)用處理器之前被調(diào)用??梢院?jiǎn)單理解為 controller 接口被調(diào)用之前執(zhí)行。

Intercepter 是鏈?zhǔn)降?,就是一個(gè)接著一個(gè)執(zhí)行。如果此方法返回 true,則會(huì)執(zhí)行下一個(gè)攔截器或者直接執(zhí)行處理器。如果此方法返回 false 或者拋出異常則終止執(zhí)行鏈,也不再調(diào)用處理器。

注意,此方法如果不返回 true,那么 postHandle 和 afterCompletion 不會(huì)被執(zhí)行。

那這個(gè)方法有什么用呢?其實(shí)可以做一些接口被調(diào)用前的預(yù)處理,例如用戶權(quán)限校驗(yàn)。

package com.chenpi;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * @Description 用戶權(quán)限驗(yàn)證攔截
 * @Author 陳皮
 * @Date 2021/6/27
 * @Version 1.0
 */
@Component
public class UserPermissionInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) {

        if (handler instanceof HandlerMethod) {

            HandlerMethod handlerMethod = (HandlerMethod) handler;

            // 獲取用戶權(quán)限校驗(yàn)注解
            UserAuthenticate userAuthenticate =
                    handlerMethod.getMethod().getAnnotation(UserAuthenticate.class);
            if (null == userAuthenticate) {
                userAuthenticate = handlerMethod.getMethod().getDeclaringClass()
                        .getAnnotation(UserAuthenticate.class);
            }
            if (userAuthenticate != null && userAuthenticate.permission()) {
                // 驗(yàn)證用戶信息
                UserContext userContext = userContextManager.getUserContext(request);
                if (null == userContext) {
                    return false;
                }
            }
        }
        return true;
    }
}

postHandle

postHandle 后置處理,會(huì)在 HandlerAdapter 調(diào)用處理器之后,但在 DispatcherServlet 渲染視圖之前被調(diào)用??梢栽诖藢?duì) ModelAndView 做一些額外的處理??梢院?jiǎn)單理解為 controller 接口被調(diào)用之后執(zhí)行。

注意,此方法在執(zhí)行鏈中的執(zhí)行順序是倒著執(zhí)行的,即先聲明的攔截器后執(zhí)行。

afterCompletion

afterCompletion 完成之后,在請(qǐng)求處理完之后被執(zhí)行,也就是渲染完視圖之后。一般用于做一些資源的清理工作,配合 preHandle 計(jì)算接口執(zhí)行時(shí)間等。

注意,和 postHandle 一樣,此方法在執(zhí)行鏈中的執(zhí)行順序也是倒著執(zhí)行的,即先聲明的攔截器后執(zhí)行。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                            Object handler, @Nullable Exception ex) {
    // 請(qǐng)求完后,清除當(dāng)前線程的用戶信息
    UserContextHolder.removeUserContext();
}

注冊(cè)攔截器

注意,我們自定義的攔截器要通過(guò) WebMvcConfigurer 的實(shí)現(xiàn)類進(jìn)行注冊(cè),才能生效。

package com.yzj.ehr.common.config;

import com.yzj.ehr.common.context.UserContextResolver;

import org.springframework.stereotype.Component;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.yzj.ehr.common.interceptor.UserPermissionInterceptor;

@Component
public class WebAppConfigurer implements WebMvcConfigurer {
    private UserPermissionInterceptor userPermissionInterceptor;
    public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) {
        this.userPermissionInterceptor = userPermissionInterceptor;
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 匹配所有接口,排除/base/test接口
        registry.addInterceptor(userPermissionInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/base/test");
    }
}

作者:陳皮的JavaLib
原文鏈接:https://blog.csdn.net/chenlixiao007/article/details/118371689

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容