上一篇文章中已經使用建造者模式對網關攔截進行封裝,存在一個問題,在鏈接器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; }