Spring Cloud(九)《服务网关Zuul 动态路由与权限过滤器》

简介: 在实际的业务开发中不只是将路由配置放到文件中,而是需要进行动态管理并且可以在变化时不用重启系统就可以更新。与此同时还需要在接口访问的时候,可以增加一些权限验证以防止恶意访问。

前言介绍

在实际的业务开发中不只是将路由配置放到文件中,而是需要进行动态管理并且可以在变化时不用重启系统就可以更新。与此同时还需要在接口访问的时候,可以增加一些权限验证以防止恶意访问。

  1. Filter过滤器,通过继承实现对应方法可以进行控制过滤;
  • PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。除了默认的过滤器类型,Zuul 还允许我们创建自定义的过滤器类型。例如,我们可以定制一种 STATIC 类型的过滤器,直接在 Zuul 中生成响应,而不将请求转发到后端的微服务。
  1. 自定义路由,同构实现SimpleRouteLocator和RefreshableRouteLocator自动刷新
  • protected Map
    locateRoutes():此方法是加载路由配置的,父类中是获取properties中的路由配置,可以通过扩展此方法,达到动态获取配置的目的
  • public Route getMatchingRoute(String path):此方法是根据访问路径,获取匹配的路由配置,父类中已经匹配到路由,可以通过路由id查找自定义配置的路由规则,以达到根据自定义规则动态分流的效果

环境准备

  • jdk 1.8、idea2018、Maven3
  • Spring Boot 2.0.6.RELEASE
  • Spring Cloud Finchley.SR2

代码示例

1itstack-demo-springcloud-08
 2├── itstack-demo-springcloud-eureka-client
 3│   └── src
 4│       └── main
 5│           ├── java
 6│           │   └── org.itstack.demo
 7│           │        ├── web
 8│           │        │   └── EurekaClientController.java
 9│           │        └── EurekaClientApplication.java
10│           └── resources   
11│               └── application.yml
12├── itstack-demo-springcloud-eureka-server
13│   └── src
14│       └── main
15│           ├── java
16│           │   └── org.itstack.demo
17│           │        └── EurekaServerApplication.java
18│           └── resources   
19│               └── application.yml
20├── itstack-demo-springcloud-hystrix-feign
21│   └── src
22│       └── main
23│           ├── java
24│           │   └── org.itstack.demo
25│           │        ├── service
26│           │        │   ├── hystrix
27│           │        │   │   └── FeignServiceHystrix.java
28│           │        │   └── FeignService.java
29│           │        ├── web
30│           │        │   └── FeignController.java
31│           │        └── FeignApplication.java
32│           └── resources   
33│               └── application.yml
34├── itstack-demo-springcloud-hystrix-ribbon
35│   └── src
36│       └── main
37│           ├── java
38│           │   └── org.itstack.demo
39│           │        ├── service
40│           │        │   └── RibbonService.java
41│           │        ├── web
42│           │        │   └── RibbonController.java      
43│           │        └── RibbonApplication.java
44│           └── resources   
45│               └── application.yml
46└── itstack-demo-springcloud-zuul
47    └── src
48        └── main
49            ├── java
50            │   └── org.itstack.demo   
51            │        ├── config
52            │        │   └── ZuulConfig.java
53            │        ├── filter
54            │        │   └── TokenFilter.java
55            │        ├── router
56            │        │   └── RouteLocator.java
57            │        ├── service
58            │        │   └── RefreshRouteService.java
59            │        └── ZuulApplication.java
60            └── resources   
61                └── application.yml

完整代码欢迎关注公众号:bugstack虫洞栈 回复“SpringCloud专题”进行下载

itstack-demo-springcloud-zuul & 动态路由与权限过滤

  1. 通过RouteLocator实现自己的动态路由配置,其实就是把配置文件内容转移到这里用代码类实现,并且可以根据需要修改为从数据库里获取。
  2. TokenFilter提供了权限验证功能,当用户访问时候会带上token否则拦截
  3. 此外还提供了自动刷新的接口,用于外部调用刷新配置
  4. 最后我们需要修改application配置,zuul中还需要排除不做路由的接口[刷新权限接口]

config/ZuulConfig.java & 路由配置类

1/**
 2 * 路由配置
 3 * 微信公众号:bugstack虫洞栈 | 专注原创技术专题案例
 4 * 论坛:http://bugstack.cn
 5 * Create by 付政委 on @2019
 6 */
 7@Configuration
 8public class ZuulConfig {
 9
10    @Autowired
11    private ZuulProperties zuulProperties;
12    @Autowired
13    private ServerProperties server;
14
15    @Bean
16    public RouteLocator routeLocator() {
17        return new RouteLocator(this.server.getServlet().getPath(), this.zuulProperties);
18    }
19
20}

filter/TokenFilter.java & 权限校验类

1/**
 2 * 微信公众号:bugstack虫洞栈 | 专注原创技术专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6public class TokenFilter extends ZuulFilter {
 7
 8    /**
 9     * 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。
10     * FilterConstants.PRE_TYPE:代表会在请求被路由之前执行。
11     * PRE、ROUTING、POST、ERROR
12     */
13    public String filterType() {
14        return FilterConstants.PRE_TYPE;
15    }
16
17    /**
18     * filter执行顺序,通过数字指定。[数字越大,优先级越低]
19     */
20    public int filterOrder() {
21        return 0;
22    }
23
24    /**
25     * 判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。
26     * 实际运用中我们可以利用该函数来指定过滤器的有效范围。
27     */
28    public boolean shouldFilter() {
29        return true;
30    }
31
32    /*
33     * 具体执行逻辑
34     */
35    public Object run() {
36        RequestContext ctx = RequestContext.getCurrentContext();
37        HttpServletRequest request = ctx.getRequest();
38        String token = request.getParameter("token");
39        if (token == null || token.isEmpty()) {
40            ctx.setSendZuulResponse(false);
41            ctx.setResponseStatusCode(401);
42            ctx.setResponseBody("refuse! token is empty");
43        }
44        return null;
45    }
46
47}

router/RouteLocator.java & 路由类

1/**
 2 * 微信公众号:bugstack虫洞栈 | 专注原创技术专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6public class RouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
 7
 8    private ZuulProperties properties;
 9
10    public RouteLocator(String servletPath, ZuulProperties properties) {
11        super(servletPath, properties);
12        this.properties = properties;
13    }
14
15    @Override
16    public void refresh() {
17        doRefresh();
18    }
19
20    @Override
21    protected Map<String, ZuulRoute> locateRoutes() {
22        LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<String, ZuulRoute>();
23        //从application.properties中加载路由信息
24        routesMap.putAll(super.locateRoutes());
25        //从db中加载路由信息
26        routesMap.putAll(routesConfigGroup());
27        //优化一下配置
28        LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
29        for (Map.Entry<String, ZuulRoute> entry : routesMap.entrySet()) {
30            String path = entry.getKey();
31            // Prepend with slash if not already present.
32            if (!path.startsWith("/")) {
33                path = "/" + path;
34            }
35            if (StringUtils.hasText(this.properties.getPrefix())) {
36                path = this.properties.getPrefix() + path;
37                if (!path.startsWith("/")) {
38                    path = "/" + path;
39                }
40            }
41            values.put(path, entry.getValue());
42        }
43        return values;
44    }
45
46    /**
47     * 路由配置组,可以从数据库中读取
48     * 基本配置与写在文件中配置类似,如下;
49     * #  routes:
50     * #    api-a:
51     * #      path: /route-a/**
52     * #      serviceId: itstack-demo-springcloud-feign
53     * #    api-b:
54     * #      path: /route-b/**
55     * #      serviceId: itstack-demo-springcloud-ribbon
56     * @return 配置组内容
57     */
58    private Map<String, ZuulRoute> routesConfigGroup() {
59        Map<String, ZuulRoute> routes = new LinkedHashMap<>();
60
61        ZuulRoute zuulRoute = new ZuulRoute();
62        zuulRoute.setId("route-a");
63        zuulRoute.setPath("/route-a/**");
64        zuulRoute.setServiceId("itstack-demo-springcloud-feign");
65        // 如果使用了注册中心,那么可以根据serviceId进行访问。
66        // zuulRoute.setUrl("http://localhost:9001");
67        zuulRoute.setRetryable(false);
68        zuulRoute.setStripPrefix(true);
69        zuulRoute.setSensitiveHeaders(new HashSet<>());
70
71        routes.put(zuulRoute.getPath(), zuulRoute);
72
73        return routes;
74    }
75
76}

service/RefreshRouteService.java & 路由刷新服务

1/**
 2 * 微信公众号:bugstack虫洞栈 | 专注原创技术专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@Service
 7public class RefreshRouteService {
 8
 9    @Autowired
10    private ApplicationEventPublisher publisher;
11
12    @Autowired
13    private RouteLocator routeLocator;
14
15    public void refreshRoute() {
16        RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
17        publisher.publishEvent(routesRefreshedEvent);
18    }
19
20}

ZuulApplication.java & 启动服务注意注解,另外提供了服务接口

1/**
 2 * 微信公众号:bugstack虫洞栈 | 专注原创技术专题案例
 3 * 论坛:http://bugstack.cn
 4 * Create by 付政委 on @2019
 5 */
 6@SpringBootApplication
 7@EnableZuulProxy
 8@EnableEurekaClient
 9@EnableDiscoveryClient
10@RestController
11public class ZuulApplication {
12
13    public static void main(String[] args) {
14        SpringApplication.run(ZuulApplication.class, args);
15    }
16
17    @Bean
18    public TokenFilter tokenFilter() {
19        return new TokenFilter();
20    }
21
22    @Autowired
23    private RefreshRouteService refreshRouteService;
24    @Autowired
25    private ZuulHandlerMapping zuulHandlerMapping;
26
27    @RequestMapping("api/refresh")
28    public String refresh(){
29        refreshRouteService.refreshRoute();
30        return "success";
31    }
32
33    @RequestMapping("api/queryRouteInfo")
34    @ResponseBody
35    public Map<String, Object> queryRouteInfo(){
36        return zuulHandlerMapping.getHandlerMap();
37    }
38
39}

application.yml & 配置文件修改,路由过滤

1server:
 2  port: 10001
 3
 4spring:
 5  application:
 6    name: itstack-demo-ddd-zuul
 7
 8eureka:
 9  client:
10    serviceUrl:
11      defaultZone: http://localhost:7397/eureka/
12
13# 动态路由,以下配置注释;
14# http://localhost:10001/route-a/api/queryUserInfo?userId=111
15# http://localhost:10001/route-b/api/queryUserInfo?userId=111
16zuul:
17   ignoredPatterns: /api/**
18#  routes:
19#    api-a:
20#      path: /route-a/**
21#      serviceId: itstack-demo-springcloud-feign
22#    api-b:
23#      path: /route-b/**
24#      serviceId: itstack-demo-springcloud-ribbon
25

测试验证

  1. 分别启动如下服务;
  2. itstack-demo-springcloud-eureka-server 服务注册与发现
  3. itstack-demo-springcloud-eureka-client 接口提供方
  4. itstack-demo-springcloud-hystrix-feign 调用端
  5. itstack-demo-springcloud-hystrix-ribbon 调用端
  6. itstack-demo-springcloud-zuul 路由服务
  7. 可测试接口列表;
  8. 路由服务:http://localhost:10001/route-a/api/queryUserInfo?userId=111&token=111
    java<br /> Hi 微信公众号:bugstack虫洞栈 | 111 &gt;: from eureka client port: 8001 From Feign<br />
  9. 刷新配置:http://localhost:10001/api/refresh
  10. 内容配置:http://localhost:10001/api/queryRouteInfo

综上总结

  1. 路由服务可以方便的帮我们控制业务类型的区分访问,同时自动刷新可以更加方便的使用网关路由
  2. 权限验证是几乎不可少的在实际开发过程中会经常用到,所有的接口必须是安全可靠的,保证数据不泄露
  3. 另外还可以考虑从入参的用户身份进行路由,这样可以把数据库路由提前,让不同用户组直接访问到不同的数据库组
目录
相关文章
|
30天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
85 0
|
30天前
|
Linux
Linux网关路由配置
Linux网关路由配置
24 0
|
30天前
|
监控 Java API
Spring cloud Hystrix 、Dashboard、API(zuul)相关报错
Spring cloud Hystrix 、Dashboard、API(zuul)相关报错
29 2
|
30天前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
165 0
|
4天前
|
Java API 开发者
Java一分钟之-Spring Cloud Gateway:API网关
【6月更文挑战第10天】Spring Cloud Gateway是Spring Cloud生态中的API网关组件,基于Spring Framework 5、Reactor和Spring Boot 2.0,支持响应式编程。它提供路由转发、过滤器链(包括预处理、路由和后处理)和断言功能。快速入门涉及添加相关依赖和配置路由规则。常见问题包括路由冲突、过滤器顺序和性能瓶颈。通过动态路由和过滤器示例,展示了其灵活性。Spring Cloud Gateway是微服务架构的有力工具,可提升系统稳定性和开发效率。
111 0
|
6天前
|
安全 Java 开发者
Java一分钟之-Spring Cloud Netflix Eureka:服务注册与发现
【6月更文挑战第8天】Spring Cloud Eureka是微服务架构的关键,提供服务注册与发现功能。本文讲解Eureka工作原理、配置、常见问题及解决方案。Eureka包含Server(管理服务状态)和Client(注册服务实例并发现服务)。快速入门包括启动Eureka Server和创建Eureka Client。常见问题涉及服务注册不上、服务下线和客户端注册信息不准确,可通过检查网络、理解自我保护机制和配置元数据解决。此外,文中还提及健康检查、安全配置和集群部署等高级实践,以增强系统健壮性和扩展性。
55 8
|
10天前
|
Linux
centos bond多网关配置 bond多网关路由
centos bond多网关配置 bond多网关路由
|
22天前
|
运维 负载均衡 API
API服务网关的作用
【5月更文挑战第23天】API服务网关是微服务架构中的统一入口,负责请求路由、组合及协议转换,隐藏内部架构细节。
|
24天前
|
Cloud Native Java 关系型数据库
【阿里云云原生专栏】构建云原生应用:基于Spring Boot与阿里云服务的全栈指南
【5月更文挑战第21天】构建云原生应用是企业数字化转型的关键,本文提供了一份基于Spring Boot和阿里云的全栈指南。涵盖从阿里云账号注册、ECS与Docker搭建,到Spring Boot项目创建、业务代码编写和部署。此外,还介绍了如何集成阿里云OSS存储、RDS数据库服务以及ACK容器服务,助力打造高效、可扩展和易管理的云原生应用。
145 3
|
30天前
|
负载均衡 Java API
构建高效微服务架构:API网关与服务熔断策略
【5月更文挑战第2天】 在微服务架构中,确保系统的高可用性与灵活性是至关重要的。本文将深入探讨如何通过实施有效的API网关和设计合理的服务熔断机制来提升分布式系统的鲁棒性。我们将分析API网关的核心职责,包括请求路由、负载均衡、认证授权以及限流控制,并讨论如何利用熔断器模式防止故障传播,维护系统的整体稳定性。文章还将介绍一些实用的技术和工具,如Netflix Zuul、Spring Cloud Gateway以及Hystrix,以帮助开发者构建一个可靠且高效的微服务环境。