Gateway与Zuul的对比
spring-cloud-Gateway
是spring-cloud
的一个子项目。而zuul
则是netflix
公司的项目,只是spring将zuul
集成在spring-cloud中使用而已。
因为zuul2.0
连续跳票和zuul1
的性能表现不是很理想,所以催生了spring团队开发了Gateway
项目。
微服务网关Zuul和Gateway的区别 - 探歌 - 博客园
开发Gateway
开发流程:
新建项目
由于gateway与springMVC的依赖不相容,所以我们不能在此项目下新建子模块,只能重新创建Spring项目:创建SpringBoot项目
springcloud项目gateway与mvc包冲突问题解决_迫壳的博客-CSDN博客
引入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.12.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.imooc</groupId>
<artifactId>cloud-mall-spring-cloud-gateway-practice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>cloud mall spring cloud gateway</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.14.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</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>
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<layout>default</layout>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>alimaven</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</pluginRepository>
</pluginRepositories>
</project>
说明; 请先复习JWT的原理
开发网关过滤器(重要!!!)
package com.imooc.cloudmallspringcloudgatewaypractice.filter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.imooc.cloudmallspringcloudgatewaypractice.model.User;
import java.util.Objects;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 描述: 网管鉴权过滤器
*/
@Component
public class AuthorizationFilter extends AbstractGatewayFilterFactory {
private User currentUser = new User();
public static final String JWT_KEY = "imooc-mall";
public static final String USER_ID = "user_id";
public static final String USER_NAME = "user_name";
public static final String USER_ROLE = "user_role";
public static final Integer ADMIN_ROLE = 2;
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
//1 对于不想对外公开的接口,拦截住
ServerHttpRequest request = exchange.getRequest();
String uri = request.getURI().toString();
if (uri.contains("/getUser")
|| uri.contains("/checkAdminRole")
|| uri.contains("/product/updateStock")
|| uri.contains("/product/detailForFeign")) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.FORBIDDEN);
return response.setComplete();
}
//2 不应该拦截的接口,要放行
if (uri.contains("image")
|| uri.contains("pay")
|| uri.contains("qrcode")
|| uri.contains("login")
|| uri.contains("adminLogin")) {
return chain.filter(exchange);
}
//3 需要鉴权的接口,要鉴权
if (uri.contains("admin")
|| uri.contains("cart")
|| uri.contains("order")
|| uri.contains("user/update")) {
request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
uri = request.getURI().getPath();
String method = request.getMethodValue();
// 2.1.从AuthenticationFilter中获取token
String key = "jwt_token";
if (!request.getHeaders().containsKey(key)) {
//如果header里没有jwt_token,就直接拦住
response.setStatusCode(HttpStatus.FORBIDDEN);
return response.setComplete();
}
String token = Objects.requireNonNull(request.getHeaders().get(key)).get(0);
Algorithm algorithm = Algorithm.HMAC256(JWT_KEY);
JWTVerifier verifier = JWT.require(algorithm).build();
try {
DecodedJWT jwt = verifier.verify(token);
currentUser.setId(jwt.getClaim(USER_ID).asInt());
Integer role = jwt.getClaim(USER_ROLE).asInt();
if (uri.contains("admin") && role != ADMIN_ROLE) {
return needAdmin(exchange);
}
currentUser.setRole(role);
currentUser.setUsername(jwt.getClaim(USER_NAME).asString());
} catch (Exception e) {
//未通过校验
return needLogin(exchange);
}
//把用户信息传递个后端服务
ServerHttpRequest host = exchange.getRequest().mutate().header(USER_ID, new String[]{String.valueOf(currentUser.getId())})
.header(USER_ROLE, new String[]{String.valueOf(currentUser.getRole())}).header(USER_NAME, new String[]{String.valueOf(currentUser.getUsername())}).build();
ServerWebExchange build = exchange.mutate().request(host).build();
return chain.filter(build);
}
return chain.filter(exchange);
};
}
private Mono<Void> needLogin(ServerWebExchange exchange) {
ServerHttpResponse response;
response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
String msg = "{\n"
+ " \"status\": 10007,\n"
+ " \"msg\": \"need right jwt_token in header\",\n"
+ " \"data\": null\n"
+ "}";
DataBuffer bodyDataBuffer = response.bufferFactory().wrap(msg.getBytes());
return response.writeWith(Mono.just(bodyDataBuffer));
}
private Mono<Void> needAdmin(ServerWebExchange exchange) {
ServerHttpResponse response;
response = exchange.getResponse();
response.setStatusCode(HttpStatus.OK);
response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
String msg = "{\n"
+ " \"status\": 10007,\n"
+ " \"msg\": \"need admin jwt_token in header\",\n"
+ " \"data\": null\n"
+ "}";
DataBuffer bodyDataBuffer = response.bufferFactory().wrap(msg.getBytes());
return response.writeWith(Mono.just(bodyDataBuffer));
}
}
说明: 学习前一定要先复习下前面所学的session升级为JWT校验
查看内部:
关于Token,前面遇到过项目实战生成JWT
这里是把信息从jwt解码存回对象,而前面是将对象里的信息存到jwt中。。。
参考下jwt生成token和验证token以及获取playload的数据,实现token拦截_心宽路阔走天下的博客-CSDN博客_jwt获取payload
配置文件
server.port=8083
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
eureka.client.service-url.defaultZone=http://localhost:8000/eureka/
spring.application.name=cloud-mall-spring-cloud-gateway-practice
spring.cloud.gateway.routes[0].id=user-route
spring.cloud.gateway.routes[0].uri=lb://cloud-mall-user
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[0].filters[1].name=AuthorizationFilter
spring.cloud.gateway.routes[1].id=category-product-route
spring.cloud.3gateway.routes[1].uri=lb://cloud-mall-category-product
spring.cloud.gateway.routes[1].predicates[0]=Path=/category-product/**
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[1].filters[1].name=AuthorizationFilter
spring.cloud.gateway.routes[2].id=cart-order-route
spring.cloud.gateway.routes[2].uri=lb://cloud-mall-cart-order
spring.cloud.gateway.routes[2].predicates[0]=Path=/cart-order/**
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[2].filters[1].name=AuthorizationFilter