基於【 責任鏈模式】二 || 網關zuul過濾器封裝

1、基於責任鏈模式封裝網關攔截

上一篇文章中已經使用建造者模式對網關攔截進行封裝,存在一個問題,在鏈接器build中,每個攔截都要進行true判斷,代碼看起來冗餘,下面使用責任鏈模式封裝數據庫

一、基於責任鏈設計模式封裝: 建立網關請求攔截接口設計模式

/**
 * @Description: 基於責任鏈設計模式封裝: 網關請求攔截
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:09
 * @Version: V1.0
 */
public interface GatewayHandler {
    /**
     * Handler處理器: 網關攔截處理請求
     */
    public void service(RequestContext ctx, String ipAddress, HttpServletRequest request, HttpServletResponse response);

    /**
     * 指向下一個handler
     */
    public void setNextHandler(GatewayHandler nextGatewayHandler);

    /**
     * 獲取下一個Handler
     *
     * @return
     */
    public GatewayHandler getNextHandler();
}

二、實現接口業務邏輯api

/**
 * @Description: 相同的Handler業務邏輯重構
 * @Author: kevin
 * @CreateTime: 2019-08-26 23:02
 * @Version: V1.0
 */
public class BaseHandler {

    protected GatewayHandler nextGatewayHandler;

    public void setNextHandler(GatewayHandler nextGatewayHandler) {
        this.nextGatewayHandler=nextGatewayHandler;
    }

    /**
     * 網關攔截
     * @param ctx
     * @param code
     * @param errorMsg
     */
    protected void resultError(RequestContext ctx, String errorMsg) {
        ctx.setResponseStatusCode(401);
        // 網關響應爲false 不會轉發服務
        ctx.setSendZuulResponse(false);
        ctx.setResponseBody(errorMsg);

    }
}
/**
 * @Description: [流程1] 基於責任鏈設計模式封裝: 黑名單攔截
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:17
 * @Version: V1.0
 */
@Slf4j
//@Component
public class BlackBlockHandler extends BaseHandler implements GatewayHandler {



    @Override
    public void service(RequestContext ctx, String ipAddress, HttpServletRequest request, HttpServletResponse response) {
        // 4.從數據庫動態讀取,判斷是黑名單,設置網關響應爲false
        if("127.0.0.1".equals(ipAddress)){
            resultError(ctx, "ip:" + ipAddress + ",Insufficient access rights");
            // 直接中止了,不繼續走後面的Handler
            return;
        }
        log.info(">>>>>>ip:{},驗證經過>>>>>>>", ipAddress);
        // 執行下一個流程Handler
        nextGatewayHandler.service(ctx,ipAddress,request,response);
    }



    @Override
    public GatewayHandler getNextHandler() {
        return null;
    }


}
/**
 * @Description: [流程2] 基於責任鏈設計模式封裝: 參數驗籤攔截
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:18
 * @Version: V1.0
 */
@Slf4j
//@Component
public class ParamsValidateHandler extends BaseHandler  implements GatewayHandler {
    @Override
    public void service(RequestContext ctx, String ipAddress, HttpServletRequest request, HttpServletResponse response) {
        // 5.外網傳遞參數簽名攔截
        Map<String, String> verifyMap = SignUtil.toVerifyMap(request.getParameterMap(), false);
        if(!SignUtil.verify(verifyMap)){
            resultError(ctx, "ip:" + ipAddress + ",Sign fail");
            return;
        }
        // 執行下一個流程Handler
        nextGatewayHandler.service(ctx,ipAddress,request,response);
    }

    @Override
    public void setNextHandler(GatewayHandler gatewayHandler) {

    }

    @Override
    public GatewayHandler getNextHandler() {
        return null;
    }
}
/**
 * @Description: [流程3] 基於責任鏈設計模式封裝: API權限控制
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:19
 * @Version: V1.0
 */
@Slf4j
//@Component
public class ApiAuthorizeHandler extends BaseHandler implements GatewayHandler {
    @Override
    public void service(RequestContext ctx, String ipAddress, HttpServletRequest request, HttpServletResponse response) {
        String servletPath = request.getServletPath();
        log.info(">>>>>servletPath:" + servletPath + ",servletPath.substring(0, 5):" + servletPath.substring(0, 5));
        // 內部服務調用不須要accessToken驗證,若是public開頭,表示受權公司訪問接口
        if (!servletPath.substring(0, 7).equals("/public")) {
            // 執行下一個流程Handler
            nextGatewayHandler.service(ctx,ipAddress,request,response);
            return;
        }
        String accessToken = request.getParameter("accessToken");
        log.info(">>>>>accessToken驗證:" + accessToken);
        if (StringUtils.isEmpty(accessToken)) {
            resultError(ctx, "AccessToken cannot be empty");
            return;
        }
        // 調用接口驗證accessToken是否失效
        BaseResponse<JSONObject> appInfo = verificaCodeServiceFeign.getAppInfo(accessToken);
        log.info(">>>>>>data:" + appInfo.toString());
        if (!isSuccess(appInfo)) {
            resultError(ctx, appInfo.getMsg());
            return;
        }
        // 執行下一個流程Handler
        nextGatewayHandler.service(ctx,ipAddress,request,response);
    }



    @Override
    public GatewayHandler getNextHandler() {
        return null;
    }
}

三、基於責任鏈設計模式封裝: 使用工廠獲取Handlerapp

/**
 * @Description: 基於責任鏈設計模式封裝: 使用工廠獲取Handler
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:27
 * @Version: V1.0
 */
public class FactoryHandler {

    /**
     * 責任鏈啓動方式:
     *
     * 1.將每個Handler存放到集合中實現遍歷
     *  能夠把handler放入數據庫,設置開關,不用每次修改代碼
     *
     * @return
     */
    public static GatewayHandler getOneHandler() {
        // 1.黑名單判斷
        GatewayHandler gatewayHandler1 = (GatewayHandler) SpringContextUtil.getBean("blackBlockHandler");
        // 2.api驗證簽名
        GatewayHandler gatewayHandler2 = (GatewayHandler) SpringContextUtil.getBean("paramsValidateHandler");
        gatewayHandler1.setNextHandler(gatewayHandler2);
        // 3.api接口驗證token
        GatewayHandler gatewayHandler3 = (GatewayHandler) SpringContextUtil.getBean("apiAuthorizeHandler");
        gatewayHandler2.setNextHandler(gatewayHandler3);
        return gatewayHandler1;

    }
}

四、基於責任鏈設計模式封裝: 責任鏈調用方ide

/**
 * @Description: 基於責任鏈設計模式封裝: 責任鏈調用方
 * @Author: kevin
 * @CreateTime: 2019-08-26 22:35
 * @Version: V1.0
 */
//@Component
public class ResponsibilityClient {
    /**
     * 責任鏈調用
     */
    public void responsibility(RequestContext ctx, String ipAddress, HttpServletRequest request,
                               HttpServletResponse response) {
        GatewayHandler oneHandler = FactoryHandler.getOneHandler();
        oneHandler.service(ctx, ipAddress, request, response);
    }
}

五、網關過濾器中調用ui

@Override
    public Object run() throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        // 1.獲取請求對象
        HttpServletRequest request = ctx.getRequest();
        // 2.獲取響應對象
        HttpServletResponse response = ctx.getResponse();

        // 3.獲取客戶端真實ip地址
        String ipAddr = IpUtil.getIpAddr(request);
        if (StringUtils.isEmpty(ipAddr)) {
            resultError(ctx, "未可以獲取到ip地址");
        }

        // 4 設計模式二: 基於責任鏈模式封裝
        responsibilityClient.responsibility(ctx,ipAddr,request,response);

        return null;



    }
相關文章
相關標籤/搜索