通过前面的学习,我们已经可以构建一个完整的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