插件 | 版本 |
jdk | 21 |
springboot | 3.0.11 |
springcloud | 2022.0.4 |
springcloudalibaba | 2022.0.0.0 |
nacos | 2.2.3(稳定版) |
python | 3.8 |
先创建目录,分别创建config,logs,data目录,单独创建一个容器
docker run -d \
-e MODE=standalone \
-p 8848:8848 \
-p 9848:9848 \
-p 7848:7848 \
-v /data/nacos/conf:/mnt/data3/dockerfiles/nacos/config \
-v /data/nacos/logs:/mnt/data3/dockerfiles/nacos/logs \
-v /data/nacos/data:/mnt/data3/dockerfiles/nacos/data \
--name nacos-mysql \
--restart=always \
nacos/nacos-server:v2.2.3
将配置文件拷贝出来(主要是application.properties和logback.xml)
docker cp nacos-mysql:/home/nacos/conf ./
修改mysql的信息(修改文件application.properties)
再次运行
docker run -d \
-e MODE=standalone \
-p 8848:8848 \
-p 9848:9848 \
-p 7848:7848 \
-v /data/nacos/conf:/mnt/data3/dockerfiles/nacos/config \
-v /data/nacos/logs:/mnt/data3/dockerfiles/nacos/logs \
-v /data/nacos/data:/mnt/data3/dockerfiles/nacos/data \
--name nacos-mysql \
--restart=always \
nacos/nacos-server:v2.2.3
开启服务器端口:
centos开启防火墙端口
访问 ip:port/nacos
出现此页面即为安装成功。
先贴一个pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.0.11
com.example
platform
0.0.1-SNAPSHOT
platform
platform
21
2022.0.0
2022.0.0.0
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
3.0.2
com.baomidou
mybatis-plus-boot-starter
3.5.3.2
com.mysql
mysql-connector-j
runtime
org.springframework.boot
spring-boot-starter-test
test
org.mybatis.spring.boot
mybatis-spring-boot-starter-test
3.0.2
test
org.projectlombok
lombok
edge-SNAPSHOT
javax.validation
validation-api
2.0.1.Final
org.apache.commons
commons-lang3
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-bootstrap
com.alibaba
fastjson
2.0.41
com.auth0
java-jwt
4.4.0
org.springframework.cloud
spring-cloud-loadbalancer
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
projectlombok.org
https://projectlombok.org/edge-releases
org.springframework.boot
spring-boot-maven-plugin
配置文件bootstrap.yml
spring:
application:
name: platform
cloud:
nacos:
server-addr: ip:port
config:
file-extension: yml
group: DEFAULT_GROUP
prefix: ${sping.application.name}
springboot启动类
@SpringBootApplication
@EnableFeignClients
@EnableCaching
@EnableScheduling
@EnableDiscoveryClient
@RefreshScope
public class PlatformApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformApplication.class, args);
}
}
启动后就可以将服务注册到nacos中
首先下载nacos的sdk包
pip install nacos-sdk-python
python代码
import glob
import nacos
import threading
from flask import request, send_file
from flask import Flask, Response
# nacos注册中心配置
SERVER_ADDRESS = "http://ip:port"
client = nacos.NacosClient(SERVER_ADDRESS)
def service_register():
"""
ephemeral参数:是否是临时服务,应为false;
刚才上面也提到了,如果是 非临时实例,客户端就无需主动完成心跳检测。
因此此处将服务注册为 非临时实例
"""
client.add_naming_instance(
"train", "ip", "port", ephemeral=False)
# 测试nacos
@app.route("/testNacos/", methods=["GET"])
def testNacos(testId):
resMap = {}
print("nacos: {}".format(testId))
resMap["code"] = "200"
resMap["message"] = "hello nacos"
resMap["data"] = str(testId)
response = Response(json.dumps(resMap), status=200,
content_type='application/json')
return response
if __name__ == "__main__":
# main()
threading.Timer(5, service_register).start()
app.run("0.0.0.0", 12352)
启动后就可以将服务注册到nacos中
到这里,服务注册到nacos已经完成了
@FeignClient("train")
public interface InferRpcService {
@GetMapping("/testNacos/{testId}")
VitsResponse testNacos(@PathVariable String testId);
}
测试类
@Test
public void testNacosPy(){
System.out.println(trainService.testNacos("232323"));
}
执行后
经测试没有问题
pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.0.11
com.example
gateway
0.0.1-SNAPSHOT
gateway
gateway
21
2022.0.4
2022.0.0.0
org.springframework.cloud
spring-cloud-starter-gateway
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-test
test
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-bootstrap
org.springframework.cloud
spring-cloud-starter-loadbalancer
com.auth0
java-jwt
4.4.0
com.alibaba
fastjson
2.0.41
org.apache.commons
commons-lang3
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
com.alibaba.cloud
spring-cloud-alibaba-dependencies
${spring-cloud-alibaba.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
配置文件(bootstrap.yml)
spring:
application:
name: gateway
cloud:
nacos:
server-addr: ip:port
config:
file-extension: yml
group: DEFAULT_GROUP
prefix: ${sping.application.name}
gateway:
# 下游服务https配置
httpclient:
ssl:
use-insecure-trust-manager: true
routes:
- id: platform
uri: lb://platform
predicates:
- Path=/api/platform/**
filters:
- StripPrefix=2
启动类
@RefreshScope
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
工具类
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.*;
@Slf4j
public class JWTUtils {
private static final String SING = "auth";
public static String getToken(Map map) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.MINUTE, 30);
JWTCreator.Builder builder = JWT.create();
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
String token = builder.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256(SING));
return token;
}
public static DecodedJWT verify(String token) {
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
/**
* 查看是否需要续约
*
* @param jwtToken 前端的
* @return -1过期,不需要续约 0 不需要操作 1 需要续约
*/
public static int renewed(String jwtToken) {
DecodedJWT verify = null;
try {
verify = JWT.require(Algorithm.HMAC256(SING)).build().verify(jwtToken);
if (Objects.nonNull(verify)) {
log.info("过期时间: {}", verify.getExpiresAt());
Date date = verify.getExpiresAt();
if (date.before(new Date())) {
log.info("token已过期");
return -1;
} else if (DateUtils.toLocalDateTime(date).minusMinutes(15L).isAfter(LocalDateTime.now())) {
log.info("token处于正常状态");
return 0;
} else if (DateUtils.toLocalDateTime(date).minusMinutes(15L).isBefore(LocalDateTime.now())) {
log.info("token需要续签");
return 1;
}
}
} catch (JWTVerificationException | IllegalArgumentException e) {
log.info("token已过期");
return -1;
}
log.info("token已过期");
return -1;
}
public static String doRenewed(String number) {
Map map = Collections.singletonMap("openid", number);
return getToken(map);
}
}
public class DateUtils {
public static LocalDateTime toLocalDateTime(Date date){
return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
}
全局过滤器
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.gateway.constant.Constant;
import com.example.gateway.constant.LoginConstant;
import com.example.gateway.constant.VitsCloneConstant;
import com.example.gateway.dto.response.CommonResponse;
import com.example.gateway.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
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;
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 获取请求路径
String path = request.getPath().toString();
log.info("path:{}", path);
// 当前过滤器只处理语音克隆相关的请求
if (StringUtils.contains(path, VitsCloneConstant.API_PREFIX)) {
// 如果是登录接口,直接放行
if (StringUtils.contains(path, LoginConstant.LOGIN_PATH)) {
return chain.filter(exchange);
}
// 获取请求头中的Authorization字段
String token = request.getHeaders().getFirst(LoginConstant.AUTHORIZATION_HEADER);
// 如果校验失败,返回未授权状态
if (StringUtils.isEmpty(token)) {
CommonResponse error = CommonResponse.error("无效的授权信息", "无效的授权信息");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.writeWith(Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(error))));
}
int renewed = JWTUtils.renewed(token);
if (renewed == -1) {
log.info("token已过期");
CommonResponse error = CommonResponse.error("无效的授权信息", "无效的授权信息");
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.writeWith(Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(error))));
} else if (renewed == 0) {
log.info("jwtToken状态正常,无需操作");
DecodedJWT verify = JWTUtils.verify(token);
String openid = verify.getClaims().get("openid").asString();
ServerHttpRequest modifiedRequest = exchange.getRequest()
.mutate()
.header("openId", openid)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
} else {
DecodedJWT verify = JWTUtils.verify(token);
String openid = verify.getClaims().get("openid").asString();
log.info("当前需要续约的jwtToken的用户手机号码: {}", openid);
token = JWTUtils.doRenewed(openid);
response.getHeaders().set(LoginConstant.AUTHORIZATION_HEADER, token);
ServerHttpRequest modifiedRequest = exchange.getRequest()
.mutate()
.header("openId", openid)
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -900;
}
}
常量类
public interface Constant {
String TOKEN = "token";
}
public interface LoginConstant {
String LOGIN_PATH = "/login";
String AUTHORIZATION_HEADER = "token";
}
public interface VitsCloneConstant {
String API_PREFIX="/api/platform/";
}
启动网关后,就可以通过网关访问服务了