一、springcloud的zuul网关拦截
1、黑名单拦截
2、参数验签
3、Api接口权限验证
二、网关拦截实现方式
1、继承ZuulFilter方法,实现业务逻辑
@Component @Slf4j public class GatewayFilter extends ZuulFilter { @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { // 改为true,才会走run方法 return true; } /** * 请求之前拦截处理业务逻辑 * @return * @throws ZuulException */ @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.动态获取黑名单列表,判断是黑名单,设置网关响应为false if("127.0.0.1".equals(ipAddress)){ resultError(ctx, "ip:" + ipAddress + ",Insufficient access rights"); } // 5.传递参数签名拦截 Map<String, String> verifyMap = SignUtil.toVerifyMap(request.getParameterMap(), false); if(!SignUtil.verify(verifyMap)){ resultError(ctx, "ip:" + ipAddress + ",Sign fail"); } // 6.api权限验证 String servletPath = request.getServletPath(); String accessToken = request.getParameter("accessToken");if (StringUtils.isEmpty(accessToken)) { resultError(ctx, "AccessToken cannot be empty"); } // 调用接口验证accessToken是否失效 BaseResponse<JSONObject> appInfo = verificaCodeServiceFeign.getAppInfo(accessToken);if (!isSuccess(appInfo)) { resultError(ctx, appInfo.getMsg()); } return null; } /** * 错误返回 * @param ctx * @param code * @param errorMsg */ private void resultError(RequestContext ctx, String errorMsg) { ctx.setResponseStatusCode(401); // 网关响应为false 不会转发服务 ctx.setSendZuulResponse(false); ctx.setResponseBody(errorMsg); }
三、使用建造者模式对上面代码进行封装
1、基于建造者设计模式封装: 网关权限控制
public interface GatewayBuild { /** * 黑名单拦截 */ Boolean blackBlock(RequestContext ctx, String ipAddress, HttpServletResponse response); /** * 参数验签 */ Boolean paramsValidate(RequestContext ctx, String ipAddress, HttpServletRequest request); /** * api权限控制 * * @return */ Boolean apiAuthorize(RequestContext ctx, HttpServletRequest request); }
2、基于建造者设计模式封装: 参数验证build,业务逻辑的实现
@Slf4j @Component public class VerificationBuild implements GatewayBuild { @Override public Boolean blackBlock(RequestContext ctx, String ipAddress, HttpServletResponse response) { // 4.从数据库动态读取,判断是黑名单,设置网关响应为false if("127.0.0.1".equals(ipAddress)){ resultError(ctx, "ip:" + ipAddress + ",Insufficient access rights"); return false; } log.info(">>>>>>ip:{},验证通过>>>>>>>", ipAddress); return true; } @Override public Boolean paramsValidate(RequestContext ctx, String ipAddress, HttpServletRequest request) { // 5.外网传递参数签名拦截 Map<String, String> verifyMap = SignUtil.toVerifyMap(request.getParameterMap(), false); if(!SignUtil.verify(verifyMap)){ resultError(ctx, "ip:" + ipAddress + ",Sign fail"); return false; } return true; } @Override public Boolean apiAuthorize(RequestContext ctx, HttpServletRequest request) { String servletPath = request.getServletPath(); // 内部服务调用不需要accessToken验证,如果public开头,表示授权方访问接口 if (!servletPath.substring(0, 7).equals("/public")) { return true; } String accessToken = request.getParameter("accessToken"); log.info(">>>>>accessToken验证:" + accessToken); if (StringUtils.isEmpty(accessToken)) { resultError(ctx, "AccessToken cannot be empty"); return false; } // 调用接口验证accessToken是否失效 BaseResponse<JSONObject> appInfo = verificaCodeServiceFeign.getAppInfo(accessToken); log.info(">>>>>>data:" + appInfo.toString()); if (!isSuccess(appInfo)) { resultError(ctx, appInfo.getMsg()); return false; } return true; } /** * 网关拦截 * @param ctx * @param code * @param errorMsg */ private void resultError(RequestContext ctx, String errorMsg) { ctx.setResponseStatusCode(401); // 网关响应为false 不会转发服务 ctx.setSendZuulResponse(false); ctx.setResponseBody(errorMsg); } }
3、基于建造者设计模式封装: 连接Build
@Component public class GatewayDirector { @Resource(name = "VerificationBuild") private GatewayBuild gatewayBuild; /** * 连接建造者 * @param ctx * @param ipAddress * @param response * @param request */ public void direcot(RequestContext ctx, String ipAddress, HttpServletResponse response, HttpServletRequest request){ // 1.黑名单 Boolean boolBlackBlock = gatewayBuild.blackBlock(ctx, ipAddress, response); if(!boolBlackBlock){ return; } // 2.参数验证 Boolean boolParamsValidate = gatewayBuild.paramsValidate(ctx, ipAddress, request); if(!boolParamsValidate){ return; } // 3.api权限控制 Boolean boolApiAuthorize = gatewayBuild.apiAuthorize(ctx, request); if(!boolApiAuthorize){ return; } } }
4、网关过滤器中调用
@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.基于建造者模式封装: 进行请求限制 gatewayDirector.direcot(ctx,ipAddr,response,request); return null; }