基于【 建造者模式】一 || 网关zuul过滤器封装

一、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;



    }

 

上一篇:ipaddress-5.0.2.jar 使用方法


下一篇:java实现日志操作记录