通过前面的学习,我们已经可以构建一个完整的SpringCloud微服务架构了,但是在这个基础上如果我们要实现权限验证这些我们该如何做呢?现在能想到的就是将权限验证直接写在consumer中,但是这样一来我们的逻辑就和这个权限验证融合到一起了,所以最好的方式就是能够将权限验证这些东西提出来,那么现在就该我们的zuul服务网关起作用的时候了。
一、zuul简介
zuul不仅仅提供了服务路由和均衡负载的作用,同时也可以将权限认证这些逻辑提到服务路由层面,使用们的微服务具有更高的可重用性和可测试性。
二、实现服务路由的功能
在这里我们需要借助之前创建的provider工程,然后使用zuul来对这两个服务进行路由。
(1)provider工程
在这里的provider工程和前面的provider工程大同小异,不过还是对配置文件进行一个展示和简单讲解。
spring.application.name=service-a server.port=8001 eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/上面的代码我们依然将provider注册到注册中心,并且将该服务的名字命名为servioce-a,这个服务名称在后面使用服务路由的时候是需要使用的。
注意:针对另一个类似的服务provider-b,我们将服务的名称命名为service-b。
(2)zuul工程
我们使用这个工程实现服务的路由和权限验证等功能。工程具体代码如下
需要添加的maven依赖如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>register</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Springcloud - register</name> <description>the demo of springCloud</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Brixton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
spring.application.name = api-gateway server.port = 7000 zuul.routes.api-a.path=/api-a/** zuul.routes.api-a.serviceId=service-a zuul.routes.api-b.path=/api-b/** zuul.routes.api-b.serviceId=service-b eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/上面的配置文件,我们依然将本服务注册到和provider相同的服务注册中心。同时定义了服务路由以及路由对应的path和serviceId。
程序运行的主类如下:
package com.liutao.application; import com.liutao.filter.AccessFilter; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; /** * 程序启动类 * * @author LIUTAO * @version 2017/5/24 * @see * @since */ @EnableZuulProxy @SpringCloudApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } /** * 实例化过滤器 * @return */ @Bean public AccessFilter accessFilter(){ return new AccessFilter(); } }在上面的代码中我们看见没有了@SpringBootApplication注解,那是因为使用了@SpringCloudAllication注解,而这个注解中包含了@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker注解。同时为了实现路由功能还在程序运行主类上面添加了@EnableZuulProxy注解。在程序运行主类中添加了一个过滤器bean。
过滤器的实现如下,在这个过滤器中我们实现了对用户权限的验证。
package com.liutao.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import javax.servlet.http.HttpServletRequest; /** * 过滤器 * 在请求被路由之前,检查请求中是否带有accessToken,如果有则被路由,如果没有则返回401 * * @author LIUTAO * @version 2017/4/19 * @see * @since */ public class AccessFilter extends ZuulFilter { /** * 返回一个字符代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型。 * pre:可以在请求被路由之前调用。 * routing:在路由请求时候被调用。 * post:在routing和error过滤器之后被调用。 * error:处理请求时发生错误被调用。 * @return */ @Override public String filterType() { return "pre"; } /** * 通过int定义过滤器执行的顺序 * @return */ @Override public int filterOrder() { return 0; } /** * 返回一个boolean类型来判断该过滤器是否执行,从而该方法相当于是一个过滤器的开关。 * @return */ @Override public boolean shouldFilter() { return true; } /** * 过滤器的具体逻辑 * @return */ @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); Object accessToken = request.getParameter("accessToken"); if(accessToken == null) { //设置不过滤该请求。并且返回错误码 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); return null; } return null; } }至此,我们完成了关于zuul使用的所有代码,目前就可以直接在浏览器中链接http://localhost:7000/api-a/liutao/userInfo?username=xionger&accessToken=fsfds地址进行测试,我们可以看到如果不输入token测试将返回401。
具体代码请参考gitHub地址:zuul