Spring Cloud Gateway 具有如下特性:
基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
动态路由:能够匹配任何请求属性; 可以对路由指定 Predicate(断言)和 Filter(过滤器);
集成Hystrix的断路器功能;
集成 Spring Cloud 服务发现功能;
易于编写的 Predicate(断言)和 Filter(过滤器);
请求限流功能;
支持路径重写。

项目搭建
1.引入jar包

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- Maven整个生命周期内排除内置容器,排除内置容器导出成war包可以让外部容器运行spring-boot项目-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>

2.修改配置文件application.yml 注:使用时请删除注释

#端口号
server:
port: 5055
spring:
application:
#项目名称
name: jq-gateway
cloud:
gateway:
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
#连接redis
redis:
host: localhost
port: 6379
timeout: 10000
database: 0
lettuce:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
#连接eureka
eureka:
client:
register-with-eureka: true
service-url:
defaultZone: http://localhost:5051/eureka
registry-fetch-interval-seconds: 30
fetch-registry: true
instance:
lease-expiration-duration-in-seconds: 90
lease-renewal-interval-in-seconds: 30

#需要释放的请求
filter:
ignore:
urls:
- /jq-member/**
- /fh-product/**
- /jq-search/**

创建FiterIgnoreUrl类

package com.jq.filter;

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@EqualsAndHashCode(callSuper = false)
@Component//交给spring管理
@ConfigurationProperties(prefix = "filter.ignore")//获取yml配置文件中的数据
public class FiterIgnoreUrl {

private List<String> urls;

}

创建MyGatewayFilter类

package com.jq.filter;

import cn.hutool.json.JSONUtil;
import com.jq.jwt.JWTUtil;
import com.jq.msg.RedisKeyUtils;
import com.jq.result.ResultCode;
import com.jq.result.ResultObj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;

@Component
public class MyGatewayFilter implements GlobalFilter, Ordered {

@Autowired
private FiterIgnoreUrl fiterIgnoreUrl;

@Autowired
private JWTUtil jwtUtil;

@Autowired
private RedisTemplate redisTemplate;


@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
AntPathMatcher antPathMatcher = new AntPathMatcher();
//判断哪些请求需要拦截,哪些需要释放
String path = request.getURI().getPath();
for (String url:fiterIgnoreUrl.getUrls()){
if(antPathMatcher.match(url,path)){
System.out.println("请求为:"+path+"放过拦截");
return chain.filter(exchange);
}
}

String token = request.getHeaders().getFirst("Authorization-token");
if (StringUtils.isEmpty(token)){
//登录失败重新登录
return responseData(exchange, ResultObj.error(ResultCode.LOGIN_ERROR));
}
//验证token
ResultObj resultObj = jwtUtil.verifyToken(token);
if(resultObj.getCode()!=200) {
//登录失败
return responseData(exchange,resultObj);
}

//token续签
String phone = jwtUtil.getPhone(token);
Boolean hasKey = redisTemplate.hasKey(RedisKeyUtils.getTokenKey(phone));
if (hasKey==false){
//登录失败重新登录
return responseData(exchange,ResultObj.error(ResultCode.LOGIN_ERROR));
}
redisTemplate.expire(ResultObj.error(ResultCode.LOGIN_ERROR),3, TimeUnit.HOURS);

//往redis中存放唯一值
request.mutate().headers(httpHeaders -> {
httpHeaders.add("phone",phone);
});

return chain.filter(exchange);
}



private Mono responseData(ServerWebExchange exchange, ResultObj resultObj){
ServerHttpResponse response=exchange.getResponse();
String data= JSONUtil.toJsonStr(resultObj);
DataBuffer dataBuffer=response.bufferFactory().allocateBuffer()
.write(data.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(dataBuffer));
}


@Override
public int getOrder() {
return 0;
}
}

创建JWTUtil工具类

package com.jq.jwt;

import com.jq.result.ResultCode;
import com.jq.result.ResultObj;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
@PropertySource({"classpath:jwt.properties"})
public class JWTUtil {

@Value("{user.jwtset.type}")
private String type;

@Value("{user.jwtset.alg}")
private String alg;

@Value("{user.jwtset.signing}")
private String signing;




public String createToken(String phone){
// token由三部分组成:头部、有效负载,签名
// 1.头部信息
Map<String,Object> headerMap = new HashMap<String,Object>();
headerMap.put("type",type);
headerMap.put("alg",alg);

// 2.有效负载
Map<String,Object> payload = new HashMap<>();
payload.put("phone",phone);
payload.put("date",new Date());

// 有效时间
long timeMillis = System.currentTimeMillis();
long endTime = timeMillis+6000000;

// 3.签名
String token = Jwts.builder().setHeader(headerMap)
.setClaims(payload)
.setExpiration(new Date(endTime))
.signWith(SignatureAlgorithm.HS256, "signing")
.compact();
return token;
}


public ResultObj verifyToken(String token) {
try {
Claims claims = Jwts.parser().setSigningKey("signing")
.parseClaimsJws(token)
.getBody();
return ResultObj.success(claims);
} catch (Exception e) {
return ResultObj.error(ResultCode.TOKEN_ERROR);
}
}

public String getPhone(String token){
try {
Claims claims = Jwts.parser().setSigningKey("signing")
.parseClaimsJws(token)
.getBody();
return (String) claims.get("phone");
} catch (Exception e) {
return null;
}
}
}

spring cloud gateway 使用_json


jwt.properties文件代码:

user.jwtset.type=JWT
user.jwtset.alg=HS256
user.jwtset.signing=jq1223

启动类代码:

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
@EnableEurekaClient
public class JqGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(JqGatewayApplication.class, args);
}
}

创建Code码枚举类

package com.jq.result;


public enum ResultCode {

SUCCESS(200,"操作成功"),
ERROR(500,"操作失败"),
USERNAME_PASSWORD_ISNULL(1001,"用户名或密码为空"),
USER_NOEXIST(1002,"用户不存在"),
PASSWORD_ERROR(1003,"密码错误"),
TOKEN_ERROR(1004,"身份过期,请重新登录"),
NO_PERMISSION(403,"没有权限访问该方法"),
PHONE_NULL(1005,"手机号为空"),
GET_CODE_ERROR(1006,"获取验证码失败"),
PHONE_CODE_ISBULL(1007,"手机号码或验证码不能为空"),
CODE_ERROR(1008,"验证码错误"),
PHONE_CODE_TIMEOUT(1009,"手机号码不正确或验证码过期"),
LOGIN_ERROR(1010,"登录失败请重新登录")
;

private Integer code;
private String msg;

ResultCode(Integer code, String msg) {
this.code = code;
this.msg = msg;
}

public Integer getCode() {
return code;
}

public void setCode(Integer code) {
this.code = code;
}

public String getMsg() {
return msg;
}

public void setMsg(String msg) {
this.msg = msg;
}
}

创建统一返回值类:

package com.jq.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ResultObj {

// 状态码
private Integer code;

// 信息
private String msg;

// 数据
private Object data;

public ResultObj(Integer code, String msg) {
this.code = code;
this.msg = msg;
}

public static ResultObj success(){
return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg());
}

public static ResultObj success(Object data){
return new ResultObj(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), data);
}

public static ResultObj error(ResultCode resultCode){
return new ResultObj(resultCode.getCode(), resultCode.getMsg(),null);
}


}

创建RedisKeyUtils类:

private static final String codeKey = "code:";
private static final String tokenKey = "token:";

public static String getCodeKey(String phone){
return codeKey + phone;
}
public static String getTokenKey(String phone){
return tokenKey + phone;
}

vue前端

spring cloud gateway 使用_json_02