springCloud之路API路由网关Zuul
1.简介
简单的理解就是,相当于在所有服务的调用前加了一层防火墙,
主要就是对外提供服务接口的时候,起到了请求的路由和过滤作用,也因此能够隐藏内部服务的接口细节,提高系统的安全性;
官方文档:https://github.com/Netflix/zuul/wiki/How-We-Use-Zuul-At-Netflix
2.简单实现
构建项目模块:zuul-9001 , 其实相当于弄一个特殊的服务提供者
pom.xml文件
<?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"> <parent> <artifactId>wfd360-station</artifactId> <groupId>com.wfd360.station</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>zuul-9001</artifactId> <dependencies> <dependency> <groupId>com.wfd360.station</groupId> <artifactId>common</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <!-- eureka 依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- actuator监控引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- zuul路由网关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project>
application.yml文件
server:
port: 9001
context-path: /
# 应用名称配置
spring:
application:
name: service-zuul
# eureka 注册中心配置
eureka:
instance:
hostname: localhost #eureka客户端主机实例名称
appname: service-zuul #客户端服务名称(可以随意取)
instance-id: service-zuul:9001 #客户端实例名称(可以随意取)
prefer-ip-address: true #显示ip地址
client:
service-url:
#defaultZone: http://localhost:7001/eureka #eureka的服务器地址(单机)
defaultZone: http://eureka7001.wfd360.com:7001/eureka/,http://eureka7002.wfd360.com:7002/eureka/,http://eureka7003.wfd360.com:7003/eureka/ # 集群
# 服务提供者信息
info:
version: v2
WeChat: 851298348
负责人: 姿势帝
启动类代码:
package com.wfd360; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * Created by 姿势帝-博客园 on 2020/6/25. * 欢迎添加笔者wx(851298348)共同探讨、学习! */ @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) @EnableZuulProxy public class ZuulApplication_9001 { /** * @param args */ public static void main(String[] args) { SpringApplication.run(ZuulApplication_9001.class, args); } }
3.测试
启动注册中心eureka 7001,启动服务提供者6004,启动zuul-9001
点击: http://eureka7001.wfd360.com:7001/ 查看注册中心中是否有zuul-9001的服务
点击: http://localhost:6004/lock/ticket/11 测试服务提供是否正常
通过网关访问服务规则:zuul网关ip+端口+服务提供者名称+服务提供者路由 ,案例如下
点击:http://localhost:9001/service-lock/lock/ticket/10 看能否通过网关访问服务
4.Zuul路由映射细节
http://localhost:9001/service-lock/lock/ticket/10 这样直接通过服务名称service-lock相当于把服务名称直接暴露在外面,非常的不安全.....因此,外面需要做路由映射配置.
4.1.路由映射配置
# 服务名称映射
zuul:
routes:
ticketServer.serviceId: service-lock
ticketServer.path: /sl/**
映射前的访问地址:http://localhost:9001/service-lock/lock/ticket/12
映射后的访问地址:http://localhost:9001/sl/lock/ticket/12
4.2.屏蔽根据服务名称访问的地址
上一节中虽然我们可以通过映射后的地址访问,但是大家发现映射前的地址也可以访问,这样还是不安全;
因此,我们需要屏蔽掉映射前的地址,也就是屏蔽根据服务名称访问的地址,如下:
# 服务名称映射
zuul:
ignored-services: "service-lock" # 屏蔽根据服务名称访问的地址,如果写"*",表示屏蔽所有
routes:
ticketServer.serviceId: service-lock
ticketServer.path: /sl/**
映射前的访问地址:http://localhost:9001/service-lock/lock/ticket/12 ,你会发现现在这个地址不能访问了,因为已经屏蔽了.
映射后的访问地址:http://localhost:9001/sl/lock/ticket/12 ,这个地址能正常访问.
4.3.给路由加请求上下文,即请求前缀
# 服务名称映射
zuul:
ignored-services: "service-lock" # 屏蔽根据服务名称访问的地址,如果写"*",表示屏蔽所有
prefix: /wx_851298348 # 请求上下文,即请求前缀
routes:
ticketServer.serviceId: service-lock
ticketServer.path: /sl/**
加了前缀的请求地址为:http://localhost:9001/wx_851298348/sl/lock/ticket/12
4.4.Zuul过滤器配置
就相当于,我们传统项目的登录拦截器一样,过滤掉没有登录的用户,或黑名单ip,在微服务中我们一般是过滤掉不合法的token
具体实现
第一步:定义一个过滤器类
package com.wfd360.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.log4j.Logger; import javax.servlet.http.HttpServletRequest; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 07/22 10:29 * @description */ public class TokenFilter extends ZuulFilter { private static final Logger log = Logger.getLogger(TokenFilter.class); /** * 过滤器的类型 * pre 表示请求前过滤 * * @return */ @Override public String filterType() { log.info("==========filterType============="); return "pre"; } /** * 该过滤器执行顺序,越小越先执行,实际生产中可能有多个过滤器 * * @return */ @Override public int filterOrder() { log.info("==========filterOrder============="); return 0; } /** * 是否需要执行过滤器 * return false 表示不执行 * return true 表示需要执行 * * @return */ @Override public boolean shouldFilter() { log.info("==========shouldFilter============="); return true; } /** * 过滤器具体业务 * <p> * 假设我们这里以token的长度必须大于5,否则是无效token * 当然实际生产中,我们的token一般是采用jwt机制实现的 * * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { log.info("==========run============="); RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String token = request.getParameter("token"); log.info("请求路由:" + request.getRequestURL().toString()); if (token == null || "".equals(token)) { log.error("token为空"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(900); ctx.setResponseBody("{\"message\":\"token is empty!\"}"); return null; } // token判断逻辑 if (token.length() <= 5) { log.error("token 非法"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(900); ctx.setResponseBody("{\"message\":\"token illegal!\"}"); } log.info("请求路由:" + request.getRequestURL().toString() + ",鉴权成功"); return null; } }
第二步:添加到容器
package com.wfd360.config; import com.wfd360.filter.TokenFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 姿势帝-博客园 * @address https://www.cnblogs.com/newAndHui/ * @WeChat 851298348 * @create 07/22 10:44 * @description */ @Configuration public class ZuulConfig { @Bean public TokenFilter tokenFilter() { return new TokenFilter(); } }
第三步:测试
访问:http://localhost:9001/wx_851298348/sl/lock/ticket/12?token=123456 ,成功,只要带有token,并且长度大于5都可以,其他的都会失败,大家自己进行演示!
完美!
springCloud课程与代码下载:https://www.cnblogs.com/newAndHui/p/13210228.html