场景:
前面几节已经实现了能够实现服务间进行调用,并且做到了负载均衡,但是还是有一个问题。很多的服务,没有一个统一的对外网关也是很头疼的事,更何况服务直接没有进行权限控制。如果想在AAA或BBB这样的“提供业务”的服务上加权限控制,这个很繁琐,工作量也很大,即使打成公共的jar也是很繁琐。如果使用zuul就可以很好的实现路由网关,和权限控制
第一步:创建一个新项目zuul,添加相关依赖,springboot版本是1.4.3.RELEASE
<!--引入Eureka_Server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<!-- 引入spring cloud的依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
第二步、配置路由分发和注册中心地址
server.port=8085
eureka.client.serviceUrl.defaultZone=http://localhost:8899/eureka/
spring.application.name=ZUUL
#配置zuul路由分发功能,此处api-a/index 则会访问到AAA中的index方法
#http://127.0.0.1:8085/api-a/index相当于 http://127.0.0.1:8081/index
zuul.routes.api-a.path= /api-a/**
zuul.routes.api-a.serviceId=aaa
zuul.routes.api-b.path= /api-b/**
zuul.routes.api-b.serviceId=bbb
注意:前文有2个一样的微服务,AAA和BBB,这里就是模拟 api-a开头的全部分发到AAA,api-b的全部分发到BBB.
第三步、在启动类加 @EnableZuulProxy开启zuul代理
到这里,就可以实现访问 http://127.0.0.1:8085/api-a/index相当于访问 AAA里面的/index,AAA的端口是8081.实际就是访问 http://127.0.0.1:8081/index。这里已经完成了路由分发,但是还没有做到权限控制,也就是我们的接口处于裸奔状态,下面讲如何做权限控制,思路是添加一个filter,然后过滤请求,不符合要求的中断掉。具体如下:
第四步、建一个filter来过滤请求,关键决定是否放行的参数是ctx.setSendZuulResponse(boolean ),true放行,false中断
MyFilter类
/**
* 此处自定义一个拦截器基于zuul,进行权限验证,可以集成jwt
*/
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
/**
* 定义filter的类型,有pre、route、post、error四种
* 过滤器类型选择:
* * pre 为路由前
* * route 为路由过程中
* * post 为路由过程后
* * error 为出现错误的时候
* * 同时也支持static ,返回静态的响应,详情见StaticResponseFilter的实现
* @return
*/
@Override
public String filterType() {
log.info("--------filterType");
return "pre";
}
/**
* filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否执行该过滤器,此处为true,说明需要过滤
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken == null) {
log.warn("token 不存在");
//决定是否放行路由(也叫分发这个路由),此处不放行
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token 不存在");
} catch (Exception e) {
e.printStackTrace();
}
} else {
//有 token进行放行
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
}
return null;
}
到这里已经完成了权限控制,这里做的比较简单就是看有没有一个参数叫token,有的话就放行了,这里可以集成jwt,在这里进行鉴权。其实还有一个问题:如何访问不是api-a和api-b的呢,其实直接不带api-a就行了。
还存在的问题:zuul是网关,是绝对不能停机的,那么如果有新增路由或者修改,怎么办?如果能够实现动态路由是不是就可以了,在不停机的情况下自动刷新并重载配置。以及当系统有N多个微服务时候,那么多的配置如何管理,如何动态刷新?具体实现请看下2节SpringCloud Config和Spring Bus.
相关参考:https://blog.csdn.net/forezp/article/details/69939114
https://blog.csdn.net/u011820505/article/details/79373594
 源码下载:EurekaZuul