Zuul过滤器

Zuul的github:https://github.com/Netflix/zuul

一系列的过滤器是zuul的核心,zuul的很多功能都是通过过滤器来实现的。在zuul的世界里定义了四种标准过滤器类型,这四种过滤器分别对应着请求的生命周期:

  • pre:此种过滤器在请求被路由之前执行,显然这种过滤器可以用来过滤请求(白黑名单)、安全验证等;

  • routing:此种过滤器复制将请求路由到具体的微服务上;

  • post:此种过滤器在请求被路由到微服务之后执行,可以用来统计用户行为、响应客户端等;

  • error:如果上面三种过滤器发生了错误,则执行此过滤器。

此外还支持"static"类型的过滤器,用于直接在zuul中生成response。结合抽象类ZuulFilter里的filterType属性注解来看:

/**
* to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
* "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
* We also support a "static" type for static responses see  StaticResponseFilter.
* Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
*
* @return A String representing that type
*/
abstract public String filterType();

 

Zuul过滤器_第1张图片

 

自定义Zuul Filter

自定义zuul filter非常简单,只需要继承ZuulFilte即可,现在编译一个zuul过滤器来实现过滤IP,只允许白名单里的IP允许访问功能,这个功能还是很常见的,例如你的服务器A出于安全性考虑,只允许接受供应商B服务器发出的请求调用:

import com.google.gson.Gson;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.simons.cn.util.CommonEnum;
import com.simons.cn.util.CommonResult;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 说明:自定义pre类型zuul过滤器,实现限过滤白名单IP功能
* Author:simonsfan
*/
@Slf4j
public class PreRequestZuulFilter extends ZuulFilter {
    /**
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
     * important for a filter. filterOrders do not need to be sequential.
     *
     * @return the int order of a filter
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * whether this filter works or not
     *
     * @return true:work ; false:zuulfilter not work
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * concrete zuulfilter logic,defined by yourself
     *
     * @return object which you need
     */
    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        HttpServletResponse response = currentContext.getResponse();
        String remoteIp = getIpAddrAdvanced(request);
        //实际白名单应该做成配置化,我这里写死仅为了模拟场景
        if (!remoteIp.equals("10.200.10.159")) {
            try {
                outPut(response);
            } catch (Exception e) {
                log.error("pre-zuulfilter run method exception:{}", e);
            }
        }
        return null;
    }

    /**
     * 获取客户端ip
     * @param request
     * @return
     */
    public static String getIpAddrAdvanced(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip != null && ip.indexOf(",") != -1) {
            String[] ipWithMultiProxy = ip.split(",");
            for (int i = 0; i < ipWithMultiProxy.length; ++i) {
                String eachIpSegement = ipWithMultiProxy[i];
                if (!"unknown".equalsIgnoreCase(eachIpSegement)) {
                    ip = eachIpSegement;
                    break;
                }
            }
        }
        return ip;
    }

    /**
     * 输出结果
     * @param response
     * @throws IOException
     */
    public void outPut(HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=utf-8");
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            String message = new Gson().toJson(CommonResult.success(CommonEnum.ILLEALREQUEST.getCode(), CommonEnum.ILLEALREQUEST.getMessage()));
            out.write(message.getBytes("UTF-8"));
        } catch (Exception e) {
            log.error("pre-zuulfilter error:{}", e);
        } finally {
            out.flush();
            out.close();
        }
    }
}

CommonEnum枚举(部分):

    ILLEALREQUEST("1001","非法请求!");

重载的四个方法在方法头部均有注释。接着启动类中加入自定义zuul过滤器PreRequestZuulFilter实例

import com.simons.cn.bean.PreRequestZuulFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy    //表示开启Zuul代理
public class ZuulGatewayApplication {

    @Bean
    public PreRequestZuulFilter preRequestZuulFilter(){
        return new PreRequestZuulFilter();
    }

    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class,args);
    }
}

启动zuul-gateway项目和user-provider-eureka、discovery-eureka三个项目,浏览器访问http://localhost:10010/user/getuserinfo?name=jack,效果如图:

Zuul过滤器_第2张图片

可以看到,所有非指定的IP均不能访问此服务,pre类型过滤器已经生效。

 

为zuul禁用过滤器

Zuul过滤器_第3张图片

 

由于SpringCloud为zuul定义了一些默认过滤器(并且启用了),如上截图,在某些场景下我们项目不需要这些过滤器,就要禁用这些filter。禁用也比较简单,直接在配置文件中:zuul...disable=true

zuul:
  DebugFilter:
    pre:
      disable: true

可以打断点测试一下,亲测有效!

此文项目的github:https://github.com/simonsfan/SpringCloud.git

你可能感兴趣的:(SpringCloud微服务)