1、网关应用场景
- 认证授权
- 统一外部入口
- 请求路由
- 请求限流
-
2、Spring Cloud Zuul
服务路由
- 自定义过滤器:通过实现ZuulFilter类的如下方法
filterType():过滤类型filterOrder():过滤顺序shouldFilter():是否需要过滤run():过滤逻辑A.Zuul相关依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
B.在配置文件配置路由拦截-application.yml
路由策略配置
zuul.routes对应的是多个服务的Map,然后每个服务对应的服务ID和Path等等
直接使用服务名,需要将微服务名称暴露给用户,会存在安全性问题。所以,可以自定义路径来替代微服务名称,即自定义路由策略。zuul:routes:fcant:path: /fcant-filter
统一前缀的配置方式
这样就需要通过 localhost:9000/zuul/consumer1/studentInfo/update 来进行访问了。zuul:prefix: /zuul
服务名屏蔽
zuul:ignore-services: "*"
路径屏蔽
Zuul 还可以指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将无法访问到指定的服务。通过该方式可以限制用户的权限。zuul:ignore-patterns: **/auto/**
* 代表匹配多级任意路径 代表匹配一级任意路径
敏感请求头屏蔽
默认情况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。
C.在启动类添加启用Zuul代理的注解
package com.fcant.springcloudgateway;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;@EnableZuulProxy@SpringBootApplicationpublic class SpringCloudGateWayApplication {public static void main(String[] args) {SpringApplication.run(SpringcloudgatewayApplication.class, args);}}
D.Zuul 的过滤功能-认证授权路由范例-AuthorizeFilter.java
实现自定义的 Filter 只需要继承 ZuulFilter 然后将这个过滤器类以 @Component 注解加入 Spring 容器中就行了。
过滤器类型:Pre、Routing、Post。前置Pre就是在请求之前进行过滤,Routing路由过滤器就是路由策略,而Post后置过滤器就是在 Response 之前进行过滤的过滤器。
package com.fcant.springcloudgateway.filter;import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import java.util.Objects;import java.util.UUID;/*** AuthorizeFilter* <p>* encoding:UTF-8** @author Fcant 19:23 2019/12/8*/@Componentpublic class AuthorizeFilter extends ZuulFilter {private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizeFilter.class);private static String accessToken;public AuthorizeFilter() {accessToken = UUID.randomUUID().toString();LOGGER.info("==> accessToken : {}", accessToken);}/*** 外部请求 -> zuul:pre -> 选择路由的服务:routing -> 请求服务:post -> zuul* pre: 在请求路由之前执行* routing: 在请求路由之后执行* post: 在请求到路由对应的服务之后执行* error: 在其他阶段发生错误时执行** @return filterType* @author Fcant 20:59 2019/12/8*/@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}/*** 过滤器执行的顺序:数字越小优先级约高** @return 返回代表过滤器执行顺序等级的数字* @author Fcant 21:07 2019/12/8*/@Overridepublic int filterOrder() {return 0;}/*** 需不需要执行此过滤器** @return True为执行* @author Fcant 21:07 2019/12/8*/@Overridepublic boolean shouldFilter() {return true;}/*** 具体的过滤逻辑** @return 返回值被忽略* @author Fcant 21:08 2019/12/8*/@Overridepublic Object run() throws ZuulException {// 获取请求的上下文,注意导入时导入zuul包下的,而非apache包下的RequestContext currentContext = RequestContext.getCurrentContext();HttpServletRequest request = currentContext.getRequest();String accessToken = request.getParameter("access_token");// 模拟accessToken验证授权// 使用Objects.equals(Object1, Object2)比较两个对象的一直性更具安全性if (Objects.equals(accessToken, AuthorizeFilter.accessToken)) {currentContext.setResponseStatusCode(HttpStatus.OK.value());currentContext.setResponseBody("Authorized");// 此处设置停止路由,因为模拟请求未做其他API转发处理currentContext.setSendZuulResponse(false);} else {// 如果验证不通过就返回springframework.http.HttpStatus提供的HTTP状态码currentContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());currentContext.setResponseBody(HttpStatus.UNAUTHORIZED.getReasonPhrase());// 此处设置停止路由转发,因为模拟请求未做其他API转发处理currentContext.setSendZuulResponse(false);}return null;}}
E.使用配置的服务拦截路径访问-http://localhost:8080/fcant-filter
F.为请求添加参数打印的随机Token访问状态为Authorized
G.令牌桶限流
首先会定义一个桶,如果桶里面没有满那么就会以一定固定的速率 会往里面放令牌,一个请求过来首先要从桶中获取令牌,如果没有获取到,那么这个请求就拒绝,如果获取到那么就放行。
@Component@Slf4jpublic class RouteFilter extends ZuulFilter {// 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {return -5;}@Overridepublic Object run() throws ZuulException {log.info("放行");return null;}@Overridepublic boolean shouldFilter() {RequestContext context = RequestContext.getCurrentContext();if(!RATE_LIMITER.tryAcquire()) {log.warn("访问量超载");// 指定当前请求未通过过滤context.setSendZuulResponse(false);// 向客户端返回响应码429,请求数量过多context.setResponseStatusCode(429);return false;}return true;}}
3、网关的跨域配置
A.SpringCloud GateWay网关配置跨域
SpringCloud GateWay通过参考官网跨域配置在yml文件配置即可生效
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration
spring:application:name: gatewaycloud:gateway:globalcors:cors-configurations:'[/**]':# 允许携带认证信息# 允许跨域的源(网站域名/ip),设置*为全部# 允许跨域请求里的head字段,设置*为全部# 允许跨域的method, 默认为GET和OPTIONS,设置*为全部# 跨域允许的有效期allow-credentials: trueallowed-origins: "*"allowed-headers: "*"allowed-methods: "*"max-age: 3600add-to-simple-url-handler-mapping: true
:::info
如果需要支持HTTP的预请求需要将 spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping 属性为 true 。
:::
B.SpringCloud Zuul网关配置跨域
因为spring-cloud-starter-netflix-zuul依赖默认引入了spring-boot-starter-web依赖
所以配置跨域需要通过配置类才能生效
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.UrlBasedCorsConfigurationSource;import org.springframework.web.filter.CorsFilter;/*** CorsAutoConfiguration* <p>* encoding:UTF-8** @author Fcant 上午 10:22 2021/1/5/0005*/@Configurationpublic class CorsAutoConfiguration {@Beanpublic CorsFilter corsFilter(){//配置初始化对象CorsConfiguration configuration=new CorsConfiguration();//允许跨域的域名,如果要携带cookie,不能写* ,*:代表所有的域名都可以访问configuration.addAllowedOrigin("*");configuration.setAllowCredentials(true);configuration.addAllowedMethod("*"); //代表所有的请求方法configuration.addAllowedHeader("*"); //允许携带任何头信息//初始化cors配置源对象UrlBasedCorsConfigurationSource configurationSource=new UrlBasedCorsConfigurationSource();configurationSource.registerCorsConfiguration("/**",configuration);//返回corsFilter实例,参数:cors配置源对象return new CorsFilter(configurationSource);}}
