## 前言
通过前面的学习,我们已经了解到如何使用 Feign 实现远程调用。然而,在使用过程中可能会遇到一个安全问题:微服务可能被任何人访问。为了解决这个问题,我们需要引入网关(Gateway)来对用户进行身份验证和权限校验。这样一来,所有请求都必须先经过网关,然后再转发到微服务,从而实现对微服务的保护。本文将介绍网关的功能、技术实现以及搭建过程。
### 1. 网关功能
#### 1.1 身份认证和权限校验
在用户通过身份认证后,网关会将请求转发到相应的微服务。这为微服务提供了一定程度的安全性。
#### 1.2 服务路由
网关根据请求信息判断应该将请求转发到哪个微服务,从而实现不同服务的区分和负载均衡。
#### 1.3 负载均衡
对外的服务也可能有多个实例,这时就需要网关进行负载均衡,以保证系统的稳定性和性能。
#### 1.4 请求限流
为了防止恶意用户对系统造成过大的压力,网关会对用户的请求量进行限制。
需要注意的是,Ribbon 是针对内部 userserver 做负载均衡的,而网关是针对外部 orderserver 做负载均衡的。
### 2. 网关的技术实现
目前常用的网关技术有以下两种:
#### 2.1 gataway
Gtatway 是一个新的技术,采用了响应式编程,非阻塞式,性能优越,吞吐能力强。但目前尚未得到广泛应用。
#### 2.2 zuul
Zuul 是较早的技术,基于 Servlet 实现,采用阻塞式编程,性能相对较差。尽管如此,它仍然具有一定的市场份额和应用场景。
### 3. 搭建网关服务
为了搭建一个网关服务,我们需要完成以下步骤:
1. 创建新的模块,并引入 SpringCloudGateway 依赖和 Nacos 服务发现依赖。
. 首先,在项目的pom.xml文件中添加nacos服务注册发现和网关gateway的依赖:
```xml
```
2. 接下来,创建一个启动类,例如`DemoApplication`,并添加`@EnableDiscoveryClient`注解以启用Nacos服务注册发现功能:
```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
```
3. 最后,编写路由配置及Nacos地址。路由配置由三部分组成:路由id、目标地址和路由断言(路由断言其实就是匹配规则)。路由断言用于判断请求是否符合要求,符合则转发到路由目的地。例如,以下是一个简单的路由配置示例:
```yaml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # 以负载均衡的方式访问名为user-service的服务实例
predicates:
- Path=/user/** # 当请求路径以/user/开头时,满足条件
```
网关配置
```yaml
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
gateway:
routes: # 网关路由配置
- id: user-server # 路由id,自定义,只要唯一即可
uri: lb://userserver # 路由的目标地址,lb就是负载均衡,后面跟服务名
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 只要以/user/开头就符合要求
- id: order-server
uri: lb://orderserver
predicates:
- Path=/order/**
```
注意:路由不止一个,用 `-` 来表示路由数组!
您好,根据您提供的信息,您需要在Spring Cloud项目中使用网关。网关是微服务架构中起到入口和路由控制的关键组件。它负责处理客户端请求,进行路由决策,并将请求转发到相应的微服务。
您已经添加了spring-cloud-starter-gateway依赖,但是还需要排除掉spring-boot-starter-web和spring-boot-starter-webflux的依赖。具体操作如下:
```xml
```
在配置文件中,我们编写的断言规则仅仅是字符串。这些字符串会被断言工厂读取并处理,最终转变为路由判断的条件。Spring 提供了11种基本的Predicate工厂,其中Path是我们最常用的方式。
让我们来测试一下,将时间设定在2031年之后才能访问,现在肯定是不能访问的:只有当断言规则都满足的时候才能访问成功,路径符合,但时间不符合,照样不能访问。
接下来是路由过滤器部分。
4.1 普通过滤器
GatewayFilter是网关中提供的一种过滤器,可以处理进入网关的请求,以及微服务返回的响应。路由之后并不是立即向微服务发起请求的,实际上我们还可以给路由配置各种各样的过滤器,这些过滤器最终会形成一个过滤器链,对进入网关的请求做各种处理。
当请求给了微服务,微服务处理完之后会返回一个结果,这个结果也是先到达网关。网关同样会通过过滤器逐层处理这个响应结果,最终返回给用户。断言匹配成功相当于请求通过了网关的大门,然后过滤器会对请求做一些处理(比如添加请求头、请求参数等),最后网关会将处理好的请求代理到具体的服务,做业务处理。
Spring 提供了31种不同的路由过滤器工厂。我们可以在Controller中获取一下请求头,并在控制台输出。如果要对所有的路由都生效,则可以将过滤器工厂写到default-filters中,与routes处于同一级。
4.2 全局过滤器
全局过滤器即自定义过滤器,全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的;而GlobalFilter的逻辑需要自己写代码实现,定义方式是实现GlobalFilter接口。
下面是一个案例,定义全局过滤器拦截请求,判断请求的参数是否满足以下两个条件:1) 参数中是否有authorization;2) authorization的参数值是否为admin。如果同时满足则放行,否则拦截。
首先创建AuthorizeFilter类,实现GlobalFilter接口,并重写filter方法。第一个参数用于处理业务逻辑,第二个参数是用来放行的,把请求委托给下一个过滤器去处理,其实就是调用下一个过滤器的filter方法,等同于放行。
```java
public class AuthorizeFilter implements GlobalFilter {
@Override
public void doFilter(ServerWebExchange exchange, GatewayFilterChain chain) throws Exception {
// 获取请求头中的authorization字段
String authorization = exchange.getRequest().getHeaders().getFirst("Authorization");
// 如果authorization字段不存在或者不满足条件(例如值不是admin),则拦截请求
if (authorization == null || !authorization.equals("admin")) {
// 这里可以进行相应的错误处理或者重定向操作
return;
}
// 如果authorization字段存在且满足条件,则放行请求
chain.filter(exchange);
}
}
```
过滤器在处理请求时是有执行顺序的。这种顺序可以通过两种方式设置:通过注解,或者实现`Ordered`接口。数值越小,优先级越高。以下是这两种方法的具体实现:
1. 通过注解设置:
```java
@Component
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在这里可以进行一些过滤操作
chain.doFilter(request, response);
}
}
```
然后在配置类中为该过滤器添加一个`Order`注解,指定其执行顺序:
```java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
AuthenticationFilter authenticationFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationFilter).addPathPatterns("/**").order(1); // Order值越小,优先级越高
}
}
```
2. 实现Ordered接口设置:
```java
@Component
public class MyFilter implements Filter, Ordered
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在这里进行一些过滤操作
chain.doFilter(request, response);
}
@Override
public int getOrder() {
// 这里返回一个整数,数值越小,优先级越高;如果返回负数,表示最低优先级
return Integer.MAX_VALUE; // 例如这里我们将这个过滤器设置为最高优先级
}
}
```
同样地,在配置类中为该过滤器添加一个`Order`注解,以指定其执行顺序:
```java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
MyFilter myFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myFilter).addPathPatterns("/**").order(0); // Order值越小,优先级越高,0是最小的优先级,所以这里是最先执行的过滤器
}
}
```
以下是重构后的内容:
```java
package com.zxe.gateway;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
// 定义过滤器执行的顺序,数值越小优先级越高
// 可以通过注解设置,也可以通过实现Ordered接口来设置
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono
//1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap
//2.获取参数中的authorization参数
String auth = params.getFirst("authorization");
//3.判断参数是否等于admin
if ( "admin".equals(auth)) {
//4.等于admin放行,其实是调用下一个过滤器的filter方法,等同于放行
return chain.filter(exchange);
}
//5.不等于就拦截,后面的业务不会再继续,我们一般会设置状态码返回给用户,提示未登录
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return -1;
}
}
```
根据提供的内容,微服务网关过滤器执行顺序如下:
1. 用户请求进入网关,断言匹配失败,报 404 错误,匹配成功直接将请求送入过滤器链;
2. 过滤器分为普通过滤器和自定义过滤器,普通过滤器可以在配置文件中设置,自定义过滤器需要实现 GlobalFilter 接口,它可以处理更复杂的过滤业务;
3. 过滤不通过的请求就会被拦截,报401错误,只有层层过滤都通过了,请求才会被路由到具体的服务上,处理具体的业务。
当前路由过滤器和默认过滤器的执行顺序是由 Spring 指定的,默认按照声明顺序从 1 开始递增。当过滤器的 order 值一样时,会按照默认过滤器 > 当前路由过滤器 > 全局过滤器的顺序执行。
您好,您可以在Spring Cloud Gateway的配置文件中添加相关的跨域配置。 这包括指定允许访问的域,配置允许的HTTP方法,以及其他必要的头信息。
例如,您可以在`spring.cloud.gateway`下添加以下配置:
```
globalcors: #全局的跨域处理 add-to-simple-url-handler-mapping: true #解决options请求被拦截的问题 cors-configurations: '[/**]': allowedOrigins: #允许哪些网站的跨域请求 - "http://localhost:8090" - "http://www.leyou.com" allowedMethods: #允许的跨域ajax的请求方式 - "GET" - "POST" - "DELETE" - "PUT" - "OPTIONS" allowedHeaders: "*" #允许在请求中携带的头信息 allowCredentials: true #是否允许携带cookie maxAge: 360000 #这次跨域检测的有效期
```