博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringCloud系列:利用Zuul实现统一服务网关服务,简单实现IP白名单功能
阅读量:7217 次
发布时间:2019-06-29

本文共 5126 字,大约阅读时间需要 17 分钟。

hot3.png

一、概述

上篇文章我们介绍了基于Eureka注册服务提供者和消费者,使用Feign、Ribbon、Hystrix实现服务间的调用、负载均衡及服务熔断和降级功能。本文将基于上述服务,利用SpringCloud Zull实现对外的统一网关服务,可在网关服务内实现签名验证、IP过滤、统一转发等功能,同时基于Hystrix实现对服务的监控功能

二、功能开发实现

1.创建统一网关服务

 创建普通的SpringBoot项目gateway,在pom.xml文件中增加如下依赖

org.springframework.cloud
spring-cloud-starter-eureka
org.springframework.cloud
spring-cloud-starter-zuul
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test

在GatewayApplication主方法上添加@EnableZuulProxy注解,启用服务路由功能。查看@EnableZuulProxy源码可知,其包含了服务注册和断路保护注解功能

@EnableCircuitBreaker@EnableDiscoveryClient@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Import(ZuulProxyMarkerConfiguration.class)public @interface EnableZuulProxy {}

2.服务路由配置

Spring Cloud Zuul通过与 Eureka的整合,实现了对服务实例的自动化维护,所以在使用服务路由配置的时候,我们不需要像传统路由配置方式那样为serviceId去指定具体的服务实例地址,只需要通过一组zuul.routes.<route>.pathzuul.routes.<route>.serviceId参数对的方式配置即可。

修改配置文件,配置转发到eureka-consumer服务的请求路由

spring.application.name=gatewayserver.port=9103#注册用IP地址代替服务名eureka.instance.preferIpAddress=trueeureka.instance.instance-id=${spring.cloud.client.ipAddress}:${spring.application.name}:${server.port}eureka.client.serviceUrl.defaultZone=http://10.17.5.45:9911/eureka/,http://10.17.5.46:9912/eureka/#zuul默认为所有服务开启默认的路由,为了服务安全,此处关闭zuul.ignored-services=*#自定义服务路由zuul.routes.eureka-consumer.path=/eureka-consumer/**zuul.routes.eureka-consumer.serviceId=eureka-consumer

启动服务,所有向/eureka-consumer/**的请求都会被转发到服务名为eureka-consumer的服务上去,打开postman测试请求

152215_ZO1T_2376417.png

152134_2DMc_2376417.png

从日志中可以看出,zuul从DynamicServerListLoadBalancer中根据Ribbon负载均衡算法从服务列表中选取后端服务,然后发送请求,返回结果。

对于面向服务的路由配置,除了使用pathserviceId映射的配置方式之外,还有一种更简洁的配置方式:zuul.routes.<serviceId>=<path>,其中<serviceId>用来指定路由的具体服务名,<path>用来配置匹配的请求表达式。比如上面的例子,它的路由规则等价于上面通过pathserviceId组合使用的配置方式。

zuul.routes.eureka-consumer=/eureka-consumer/**

修改配置文件,重启服务,用postman调用服务,可得同样的路由规则

152926_swyg_2376417.png

3.实现IP白名单功能

我们主要利用Zuul的过滤器来实现该功能,其过滤器还可以用来实现统一的签名和验签服务以及其他任何你需要的服务,本例实现简单的IP过滤功能

  新建IPFilter类,继承ZuulFilter,实现其方法

@Componentpublic class IPFilter extends ZuulFilter {    Logger logger= LoggerFactory.getLogger(getClass());    @Override    public String filterType() {        return "pre";    }    @Override    public int filterOrder() {        return 0;    }    @Override    public boolean shouldFilter() {        return true;    }    @Override    public Object run() {        RequestContext ctx= RequestContext.getCurrentContext();        HttpServletRequest req=ctx.getRequest();        String ipAddr=this.getIpAddr(req);        logger.info("请求IP地址为:[{}]",ipAddr);       //配置本地IP白名单,生产环境可放入数据库或者redis中        List
ips=new ArrayList
(); ips.add("172.0.0.1"); if(!ips.contains(ipAddr)){ logger.info("IP地址校验不通过!!!"); ctx.setResponseStatusCode(401); ctx.setSendZuulResponse(false); ctx.setResponseBody("IpAddr is forbidden!"); } logger.info("IP校验通过。"); return null; } /** * 获取Ip地址 * @param request * @return */ public String getIpAddr(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(); } return ip; }}

重启服务,再次发送请求,本地IP被禁止访问

160555_RhRa_2376417.png

160612_jB7o_2376417.png

在上面实现的过滤器代码中,我们通过继承ZuulFilter类并重写了下面的四个方法来实现自定义的过滤器.

  • filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由之前执行。另外还有“route”、“post”、"error”等类型,具体解释如下
  • /** * 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();
  • filterOrder:过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。
  • shouldFilter:判断该过滤器是否需要被执行。这里我们直接返回true,因此该过滤器对所有请求都会生效,实际运用中我们可以利用该函数来指定过滤器的有效范围。
  • run:过滤器的具体逻辑。IP校验不通过时我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,通过ctx.setResponseBody(body)返回body内容。

三、小结

   Demo源码地址:https://gitee.com/gengkangkang/springcloud.git

转载于:https://my.oschina.net/gengkangkang/blog/1589285

你可能感兴趣的文章
C#温故而知新学习系列之面向对象编程—类的数据成员(三)
查看>>
列表字典推导式
查看>>
HDOJ 1228 A+B(map水题)
查看>>
intellij IDEA 导入包的方法·
查看>>
Python之路番外:PYTHON基本数据类型和小知识点
查看>>
转:matlab+spider+weka
查看>>
步步为营 .NET 设计模式学习笔记 十五、Composite(组合模式)
查看>>
angular通过路由实现跳转 resource加载数据
查看>>
python try except, 异常处理
查看>>
字符串中的各种方法
查看>>
创建文件夹、新建txt文件
查看>>
js form表单 鼠标移入弹出提示功能
查看>>
LFS7.10——准备Host系统
查看>>
Redis.py客户端的命令总结【三】
查看>>
mac 安装secureCRT
查看>>
/var/adm/wtmp文件太大该怎么办?
查看>>
反应器模式 vs 观察者模式
查看>>
Algernon's Noxious Emissions POJ1121 zoj1052
查看>>
iOS-数据持久化-对象归档
查看>>
iOS开发UI篇—程序启动原理和UIApplication
查看>>