一、基于责任链模式封装网关拦截
上一篇文章中已经使用建造者模式对网关拦截进行封装,存在一个问题,在连接器build中,每一个拦截都要进行true判断,代码看起来冗余,下面使用责任链模式封装
1、基于责任链设计模式封装: 创建网关请求拦截接口
/** * @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(); }
2、实现接口业务逻辑
/** * @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; } }
3、基于责任链设计模式封装: 使用工厂获取Handler
/** * @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; } }
4、基于责任链设计模式封装: 责任链调用方
/** * @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); } }
5、网关过滤器中调用
@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; }