Compare commits
44 Commits
e1f5dcc855
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2daec6b123 | ||
|
|
7e19ba4d06 | ||
|
|
58951ff9b6 | ||
|
|
9124256f01 | ||
|
|
7f69eebedf | ||
|
|
e00e7f3e5e | ||
|
|
a5c0695488 | ||
|
|
c8d1bc6985 | ||
|
|
3b11905b55 | ||
|
|
94379b9a16 | ||
|
|
e642dbf041 | ||
|
|
e7ef16b8ab | ||
|
|
32bd7c7808 | ||
|
|
a98ba4222c | ||
|
|
472c349220 | ||
|
|
2ebad70036 | ||
|
|
5ed0a0a288 | ||
|
|
ffd45a4f43 | ||
|
|
1b744635d6 | ||
|
|
7422418dff | ||
|
|
9d3795f34f | ||
|
|
8e2ba26fa7 | ||
|
|
b697d86fef | ||
|
|
89e6bda78d | ||
|
|
edb0c01ec0 | ||
|
|
af8fedfee4 | ||
|
|
e3158828d6 | ||
|
|
ad50e0122a | ||
|
|
794c077aa1 | ||
|
|
5ae0ab58d8 | ||
|
|
a6e881eaf0 | ||
|
|
2b56b5f690 | ||
|
|
fc4f159f40 | ||
|
|
4e3ac6f973 | ||
|
|
6ddca902be | ||
|
|
fdda674368 | ||
|
|
7fac582123 | ||
|
|
adce180ac3 | ||
|
|
a29a4b2dc4 | ||
|
|
e992c7e47f | ||
|
|
e2c30bd918 | ||
|
|
f060d1ab44 | ||
|
|
a539e48edf | ||
|
|
77efb99f51 |
@@ -4,7 +4,8 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_and_deploy:
|
build_and_deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: java21
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
build_status: ${{ job.status }}
|
build_status: ${{ job.status }}
|
||||||
build_url: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
|
build_url: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
|
||||||
@@ -26,52 +27,20 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
- name: 2.Set up JDK 21
|
|
||||||
uses: actions/setup-java@v5
|
- name: 3.缓存 Maven 依赖
|
||||||
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
java-version: '21'
|
path: ~/.m2/repository
|
||||||
distribution: 'temurin'
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-maven-
|
||||||
|
|
||||||
- name: 3.设置JAVA Maven 环境
|
- name: 4.构建项目
|
||||||
run: |
|
run: |
|
||||||
# 适配root/普通用户
|
java -version
|
||||||
SUDO=""
|
|
||||||
[ "$(id -u)" != "0" ] && SUDO="sudo"
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
$SUDO apt update && $SUDO apt install -y wget tar --no-install-recommends
|
|
||||||
|
|
||||||
# 下载Maven
|
|
||||||
MAVEN_VERSION="3.9.11"
|
|
||||||
MAVEN_TAR="apache-maven-${MAVEN_VERSION}-bin.tar.gz"
|
|
||||||
MAVEN_URL="https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/${MAVEN_TAR}"
|
|
||||||
wget --no-verbose -O /tmp/${MAVEN_TAR} ${MAVEN_URL}
|
|
||||||
|
|
||||||
# 解压+软链接
|
|
||||||
$SUDO tar -xzf /tmp/${MAVEN_TAR} -C /usr/local/
|
|
||||||
$SUDO ln -sf /usr/local/apache-maven-${MAVEN_VERSION} /usr/local/maven
|
|
||||||
|
|
||||||
# 配置PATH
|
|
||||||
echo "/usr/local/maven/bin" >> $GITHUB_PATH
|
|
||||||
export PATH="/usr/local/maven/bin:$PATH"
|
|
||||||
|
|
||||||
# 验证
|
|
||||||
mvn -v
|
mvn -v
|
||||||
|
mvn clean package -DskipTests
|
||||||
- name: 4.构建jar包
|
|
||||||
run: |
|
|
||||||
echo "===== 开始构建JAR包 ====="
|
|
||||||
# 新增:打印当前构建分支(两种方式双重确认)
|
|
||||||
echo "当前工作目录分支:$(git branch --show-current)"
|
|
||||||
echo "Gitea检出分支:${{ github.ref_name }}"
|
|
||||||
echo "预期构建分支: master"
|
|
||||||
echo "========================"
|
|
||||||
mvn -B clean install -DskipTests -Pdev 2>&1
|
|
||||||
# 检查构建是否成功
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "JAR包构建失败!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: 5.生成Dockerfile
|
- name: 5.生成Dockerfile
|
||||||
run: |
|
run: |
|
||||||
@@ -93,7 +62,7 @@ jobs:
|
|||||||
cat > docker-compose.yml << 'EOF'
|
cat > docker-compose.yml << 'EOF'
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
aida_back:
|
master-aida-gateway:
|
||||||
container_name: master-aida-gateway
|
container_name: master-aida-gateway
|
||||||
build: .
|
build: .
|
||||||
volumes:
|
volumes:
|
||||||
@@ -102,46 +71,41 @@ jobs:
|
|||||||
- ./temp:/temp
|
- ./temp:/temp
|
||||||
- ./uploads:/temp/uploads
|
- ./uploads:/temp/uploads
|
||||||
ports:
|
ports:
|
||||||
- '10094:5567'
|
- '10094:10094'
|
||||||
restart: always
|
restart: always
|
||||||
EOF
|
EOF
|
||||||
# 验证docker-compose.yml生成
|
# 验证docker-compose.yml生成
|
||||||
echo "docker-compose.yml内容:"
|
echo "docker-compose.yml内容:"
|
||||||
cat docker-compose.yml
|
cat docker-compose.yml
|
||||||
|
|
||||||
- name: 7.安装SSH工具
|
- name: 7.上传jar到远程服务器
|
||||||
run: |
|
uses: appleboy/scp-action@master
|
||||||
$SUDO apt install -y sshpass openssh-client --no-install-recommends
|
with:
|
||||||
# 配置SSH免密
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
mkdir -p ~/.ssh
|
port: 22
|
||||||
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
|
username: ${{ secrets.SERVER_USER }}
|
||||||
chmod 600 ~/.ssh/id_rsa
|
key: ${{ secrets.SSH_KEY }}
|
||||||
ssh-keyscan -H ${{ secrets.SERVER_HOST }} >> ~/.ssh/known_hosts
|
source: "target/*.jar,Dockerfile,docker-compose.yml"
|
||||||
|
target: ${{ env.REMOTE_DEPLOY_PATH }}
|
||||||
|
preserve_host_directory_structure: false
|
||||||
|
|
||||||
- name: 8.同步文件到远程服务器
|
- name: 8. 重启 Docker 服务
|
||||||
run: |
|
uses: appleboy/ssh-action@master # 👈 专门执行命令的 action
|
||||||
echo "===== 同步文件到远程服务器 ====="
|
with:
|
||||||
# 使用scp同步文件
|
host: ${{ secrets.SERVER_HOST }}
|
||||||
scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
username: ${{ secrets.SERVER_USER }}
|
||||||
./target/*.jar ./Dockerfile ./docker-compose.yml \
|
key: ${{ secrets.SSH_KEY }}
|
||||||
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ env.REMOTE_DEPLOY_PATH }} 2>&1
|
key_base64: true
|
||||||
|
script: |
|
||||||
- name: 9.部署和运行服务
|
echo "========= 进入部署目录 ========="
|
||||||
run: |
|
|
||||||
echo "===== 开始部署服务 ====="
|
|
||||||
# SSH执行部署命令
|
|
||||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
|
||||||
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} << 'EOF_SSH'
|
|
||||||
cd ${{ env.REMOTE_DEPLOY_PATH }}
|
cd ${{ env.REMOTE_DEPLOY_PATH }}
|
||||||
echo "停止旧容器..."
|
ls -l
|
||||||
docker compose down || true
|
|
||||||
echo "清理Docker资源..."
|
echo "========= 停止旧服务 ========="
|
||||||
docker system prune -f
|
docker compose down
|
||||||
echo "构建镜像..."
|
|
||||||
docker compose build --no-cache
|
echo "========= 启动新服务 ========="
|
||||||
echo "启动服务..."
|
docker compose up -d --build
|
||||||
docker compose up -d
|
|
||||||
echo "验证容器状态..."
|
echo "========= 查看运行状态 ========="
|
||||||
docker compose ps
|
docker compose ps
|
||||||
echo "部署完成!"
|
|
||||||
EOF_SSH
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
/.idea/
|
/.idea/
|
||||||
/target/
|
/target/
|
||||||
|
/log/
|
||||||
|
|||||||
22
pom.xml
22
pom.xml
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>21</java.version>
|
<java.version>21</java.version>
|
||||||
<spring-cloud.version>2023.0.1</spring-cloud.version>
|
<spring-cloud.version>2023.0.4</spring-cloud.version>
|
||||||
<spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
|
<spring-cloud-alibaba.version>2023.0.3.4</spring-cloud-alibaba.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -62,17 +62,11 @@
|
|||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Jackson -->
|
<!-- Hutool -->
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Hutool (aligned with aida_seller 5.8.26) -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>5.8.26</version>
|
<version>5.8.23</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- Redis (for token blacklist) -->
|
<!-- Redis (for token blacklist) -->
|
||||||
@@ -100,6 +94,12 @@
|
|||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Boot Logging(显式引入,确保 logback 正确初始化) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-logging</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Knife4j Gateway Aggregation -->
|
<!-- Knife4j Gateway Aggregation -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.xiaoymin</groupId>
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
@@ -145,6 +145,8 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<!-- 强制工作目录为模块根目录,确保 ./log 指向项目目录而非 Maven 安装目录 -->
|
||||||
|
<workingDirectory>${project.basedir}</workingDirectory>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>
|
<exclude>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
|
|||||||
79
src/main/java/com/aida/gateway/common/response/Response.java
Normal file
79
src/main/java/com/aida/gateway/common/response/Response.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package com.aida.gateway.common.response;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName Response
|
||||||
|
* @Description success代表响应成功 fail代表主动响应失败 error代表系统异常
|
||||||
|
* @Author dwjian
|
||||||
|
* @Date 2019/9/8 21:48
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Response<T> implements Serializable {
|
||||||
|
|
||||||
|
private int errCode;
|
||||||
|
private String errMsg;
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
public static <T> Response<T> success() {
|
||||||
|
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> success(T data) {
|
||||||
|
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> success(int code, T data) {
|
||||||
|
return success(code, ResultEnum.SUCCESS.getMsg(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> success(int code, String msg, T data) {
|
||||||
|
return getResponse(code, msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> fail(String msg) {
|
||||||
|
return fail(ResultEnum.FAIL.getCode(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> fail(T data) {
|
||||||
|
return fail(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> fail(ResultEnum resultEnum) {
|
||||||
|
return fail(resultEnum.getCode(), resultEnum.getMsg(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> fail(int code, String msg) {
|
||||||
|
return fail(code, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> fail(int code, String msg, T data) {
|
||||||
|
return getResponse(code, msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> error(String msg) {
|
||||||
|
return error(ResultEnum.ERROR.getCode(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> error(T data) {
|
||||||
|
return error(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> error(int code, String msg) {
|
||||||
|
return error(code, msg, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Response<T> error(int code, String msg, T data) {
|
||||||
|
return getResponse(code, msg, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Response<T> getResponse(int code, String msg, T data) {
|
||||||
|
return new Response<>(code, msg, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.aida.gateway.common.response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName ResultEnum
|
||||||
|
* @Description 响应结果枚举
|
||||||
|
* @Author dwjian
|
||||||
|
* @Date 2019/9/8 21:58
|
||||||
|
*/
|
||||||
|
public enum ResultEnum {
|
||||||
|
|
||||||
|
SUCCESS(true, 0, "SUCCESS"),
|
||||||
|
FAIL(false, -1, "FAIL"),
|
||||||
|
ERROR(false, -1, "system error!"),
|
||||||
|
PARAMETER_ERROR(false, -2, "parameter error!"),
|
||||||
|
|
||||||
|
NO_LOGIN(false, -100, "User not logged in"),
|
||||||
|
NO_PERMISSION(false, -200, "No access"),
|
||||||
|
ACCOUNT_LOCK(false, -300, "Account frozen"),
|
||||||
|
|
||||||
|
PROMPT(false, 1, "Prompt"),
|
||||||
|
WARNING(false, 2, "Warning"),
|
||||||
|
|
||||||
|
;
|
||||||
|
private int code;
|
||||||
|
private String msg;
|
||||||
|
private boolean isOK;
|
||||||
|
|
||||||
|
|
||||||
|
ResultEnum(boolean isOK, int code, String msg) {
|
||||||
|
this.isOK = isOK;
|
||||||
|
this.code = code;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMsg(String msg) {
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOK() {
|
||||||
|
return isOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOK(boolean OK) {
|
||||||
|
isOK = OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,5 +19,13 @@ public class GatewayAuthProperties {
|
|||||||
|
|
||||||
private List<String> ignorePaths;
|
private List<String> ignorePaths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可选认证路径:token 有则解析并写入下游请求头,无则放行。
|
||||||
|
* 与 ignorePaths 的区别:ignorePaths 完全跳过认证逻辑;
|
||||||
|
* optionalAuthPaths 仍然尝试解析 token,有 token 时正常写入 X-User-Id / X-User-Info,
|
||||||
|
* 无 token 时才放行,确保已登录用户的信息能正确传递。
|
||||||
|
*/
|
||||||
|
private List<String> optionalAuthPaths;
|
||||||
|
|
||||||
private boolean blacklistEnabled = true;
|
private boolean blacklistEnabled = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.aida.gateway.controller;
|
||||||
|
|
||||||
|
import com.aida.gateway.common.response.Response;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/gateway")
|
||||||
|
public class HealthController {
|
||||||
|
|
||||||
|
@GetMapping("/healthy")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public Response<Map<String, Integer>> checkStatus() {
|
||||||
|
Map<String, Integer> returnMap = new HashMap<>();
|
||||||
|
returnMap.put("code", 200);
|
||||||
|
return Response.success(returnMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,10 @@ import io.jsonwebtoken.Jwts;
|
|||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.data.redis.core.ReactiveRedisTemplate;
|
import org.springframework.data.redis.core.ReactiveRedisTemplate;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
@@ -32,16 +34,22 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
* Gateway 全局鉴权过滤器。
|
* Gateway 全局鉴权过滤器。
|
||||||
* <p>
|
* <p>
|
||||||
* 流程:
|
* 流程:
|
||||||
* 1. 白名单路径直接放行
|
* 1. 放过 OPTIONS 预检请求,由全局 CORS 配置处理
|
||||||
* 2. 从请求头读取 JWT,验证签名和有效期
|
* 2. 白名单路径直接放行
|
||||||
* 3. 检查 Redis 黑名单(logout 后 token 被拉黑)
|
* 3. 从请求头读取 JWT,验证签名和有效期
|
||||||
* 4. 将用户 ID 和用户信息 JSON 写入下游请求头
|
* 4. 检查 Redis 黑名单(logout 后 token 被拉黑)
|
||||||
* 5. 失败返回 401 JSON
|
* 5. 将用户 ID 和用户信息 JSON 写入下游请求头
|
||||||
|
* 6. 失败返回 401 JSON
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GlobalAuthWebFilter implements WebFilter {
|
public class GlobalAuthWebFilter implements WebFilter, Ordered {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return Ordered.LOWEST_PRECEDENCE - 1;
|
||||||
|
}
|
||||||
|
|
||||||
private final GatewayAuthProperties authProperties;
|
private final GatewayAuthProperties authProperties;
|
||||||
@Qualifier("reactiveRedisTemplate")
|
@Qualifier("reactiveRedisTemplate")
|
||||||
@@ -53,24 +61,47 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||||
String path = exchange.getRequest().getURI().getPath();
|
String path = exchange.getRequest().getURI().getPath();
|
||||||
|
|
||||||
// 1. 白名单直接放行
|
if ("OPTIONS".equalsIgnoreCase(exchange.getRequest().getMethod().name())) {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 白名单直接放行(完全跳过认证)
|
||||||
if (isIgnoredPath(path)) {
|
if (isIgnoredPath(path)) {
|
||||||
return chain.filter(exchange);
|
return chain.filter(exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 提取 token
|
// 3. 可选认证路径:token 有则解析,无则放行
|
||||||
|
if (isOptionalAuthPath(path)) {
|
||||||
|
String rawHeader = exchange.getRequest().getHeaders()
|
||||||
|
.getFirst(authProperties.getJwtTokenHeader());
|
||||||
|
if (StrUtil.isBlank(rawHeader)) {
|
||||||
|
// 无 token,直接放行,不写任何 header
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
// 有 token,正常走解析流程(复用下面的验证逻辑)
|
||||||
|
return processTokenWithAuthCheck(exchange, chain, rawHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 其他路径:必须有 token
|
||||||
String rawHeader = exchange.getRequest().getHeaders()
|
String rawHeader = exchange.getRequest().getHeaders()
|
||||||
.getFirst(authProperties.getJwtTokenHeader());
|
.getFirst(authProperties.getJwtTokenHeader());
|
||||||
if (StrUtil.isBlank(rawHeader)) {
|
if (StrUtil.isBlank(rawHeader)) {
|
||||||
return writeUnauthorized(exchange, AuthConstants.MSG_MISSING_TOKEN);
|
return writeUnauthorized(exchange, AuthConstants.MSG_MISSING_TOKEN);
|
||||||
}
|
}
|
||||||
|
return processTokenWithAuthCheck(exchange, chain, rawHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的 token 解析与认证流程:解析 JWT → 黑名单检查 → 写入下游 header。
|
||||||
|
* 专供可选认证路径中有 token 的情况,以及普通路径的鉴权。
|
||||||
|
*/
|
||||||
|
private Mono<Void> processTokenWithAuthCheck(ServerWebExchange exchange, WebFilterChain chain, String rawHeader) {
|
||||||
String token = rawHeader;
|
String token = rawHeader;
|
||||||
if (rawHeader.startsWith(authProperties.getJwtTokenPrefix())) {
|
if (rawHeader.startsWith(authProperties.getJwtTokenPrefix())) {
|
||||||
token = rawHeader.substring(authProperties.getJwtTokenPrefix().length());
|
token = rawHeader.substring(authProperties.getJwtTokenPrefix().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. JWT 签名验证
|
// JWT 签名验证
|
||||||
Claims claims;
|
Claims claims;
|
||||||
try {
|
try {
|
||||||
claims = parseToken(token);
|
claims = parseToken(token);
|
||||||
@@ -79,7 +110,7 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
return writeUnauthorized(exchange, AuthConstants.MSG_TOKEN_EXPIRED);
|
return writeUnauthorized(exchange, AuthConstants.MSG_TOKEN_EXPIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 解析用户信息
|
// 解析用户信息
|
||||||
AuthPrincipalVo principal;
|
AuthPrincipalVo principal;
|
||||||
try {
|
try {
|
||||||
principal = objectMapper.readValue(claims.getSubject(), AuthPrincipalVo.class);
|
principal = objectMapper.readValue(claims.getSubject(), AuthPrincipalVo.class);
|
||||||
@@ -92,7 +123,7 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
return writeUnauthorized(exchange, AuthConstants.MSG_INVALID_TOKEN);
|
return writeUnauthorized(exchange, AuthConstants.MSG_INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 黑名单检查(仅当启用时)
|
// 黑名单检查
|
||||||
if (authProperties.isBlacklistEnabled()) {
|
if (authProperties.isBlacklistEnabled()) {
|
||||||
String blacklistKey = AuthConstants.BLACKLIST_PREFIX + principal.getId();
|
String blacklistKey = AuthConstants.BLACKLIST_PREFIX + principal.getId();
|
||||||
return redisTemplate.hasKey(blacklistKey).flatMap(isBlacklisted -> {
|
return redisTemplate.hasKey(blacklistKey).flatMap(isBlacklisted -> {
|
||||||
@@ -139,6 +170,18 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOptionalAuthPath(String requestUri) {
|
||||||
|
if (authProperties.getOptionalAuthPaths() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (String pattern : authProperties.getOptionalAuthPaths()) {
|
||||||
|
if (pathMatcher.match(pattern, requestUri)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private Claims parseToken(String token) {
|
private Claims parseToken(String token) {
|
||||||
SecretKey key = buildSigningKey();
|
SecretKey key = buildSigningKey();
|
||||||
return Jwts.parser()
|
return Jwts.parser()
|
||||||
@@ -160,6 +203,11 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
ServerHttpResponse response = exchange.getResponse();
|
ServerHttpResponse response = exchange.getResponse();
|
||||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
String origin = exchange.getRequest().getHeaders().getFirst(HttpHeaders.ORIGIN);
|
||||||
|
if (origin != null) {
|
||||||
|
response.getHeaders().set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||||
|
response.getHeaders().set(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
|
||||||
|
}
|
||||||
String body = String.format("{\"code\":401,\"message\":\"%s\"}", message);
|
String body = String.format("{\"code\":401,\"message\":\"%s\"}", message);
|
||||||
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
|
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
|
||||||
return response.writeWith(Mono.just(buffer));
|
return response.writeWith(Mono.just(buffer));
|
||||||
|
|||||||
@@ -4,14 +4,36 @@
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
server:
|
server:
|
||||||
port: 5569
|
port: 10094
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: aida-gateway
|
name: aida-gateway
|
||||||
cloud:
|
cloud:
|
||||||
gateway:
|
gateway:
|
||||||
|
globalcors:
|
||||||
|
cors-configurations:
|
||||||
|
'[/**]':
|
||||||
|
allowed-origin-patterns: "*"
|
||||||
|
allowed-methods:
|
||||||
|
- GET
|
||||||
|
- POST
|
||||||
|
- PUT
|
||||||
|
- DELETE
|
||||||
|
- OPTIONS
|
||||||
|
- PATCH
|
||||||
|
allowed-headers: "*"
|
||||||
|
allow-credentials: true
|
||||||
|
max-age: 3600
|
||||||
|
default-filters:
|
||||||
|
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials
|
||||||
|
# ---------- 路由配置 ----------
|
||||||
routes:
|
routes:
|
||||||
|
# 多实例部署时推送会失效,升级多实例要注意ws改造
|
||||||
|
- id: aida-back-websocket
|
||||||
|
uri: lb://aida-back
|
||||||
|
predicates:
|
||||||
|
- Path=/notification/**
|
||||||
- id: aida-back
|
- id: aida-back
|
||||||
uri: lb://aida-back
|
uri: lb://aida-back
|
||||||
predicates:
|
predicates:
|
||||||
@@ -28,6 +50,12 @@ spring:
|
|||||||
uri: http://18.167.251.121:9994
|
uri: http://18.167.251.121:9994
|
||||||
predicates:
|
predicates:
|
||||||
- Path=/python/**
|
- Path=/python/**
|
||||||
|
- id: aida-buyer
|
||||||
|
uri: lb://aida-buyer
|
||||||
|
predicates:
|
||||||
|
- Path=/buyer/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
# ---------- Knife4j 网关聚合配置 ----------
|
# ---------- Knife4j 网关聚合配置 ----------
|
||||||
knife4j:
|
knife4j:
|
||||||
gateway:
|
gateway:
|
||||||
@@ -45,6 +73,11 @@ knife4j:
|
|||||||
service-name: aida-seller
|
service-name: aida-seller
|
||||||
context-path: /seller
|
context-path: /seller
|
||||||
order: 2
|
order: 2
|
||||||
|
- name: 买家端服务 (Buyer)
|
||||||
|
url: /buyer/v3/api-docs
|
||||||
|
service-name: aida-buyer
|
||||||
|
context-path: /buyer
|
||||||
|
order: 3
|
||||||
|
|
||||||
# ---------- Gateway JWT 认证(gateway 独有) ----------
|
# ---------- Gateway JWT 认证(gateway 独有) ----------
|
||||||
gateway:
|
gateway:
|
||||||
@@ -54,6 +87,7 @@ gateway:
|
|||||||
jwt-token-prefix: Bearer-
|
jwt-token-prefix: Bearer-
|
||||||
blacklist-enabled: true
|
blacklist-enabled: true
|
||||||
ignore-paths:
|
ignore-paths:
|
||||||
|
# Static resources & docs
|
||||||
- /favicon.ico
|
- /favicon.ico
|
||||||
- /doc.html
|
- /doc.html
|
||||||
- /swagger-ui.html
|
- /swagger-ui.html
|
||||||
@@ -66,37 +100,12 @@ gateway:
|
|||||||
- /v3/api-docs/**
|
- /v3/api-docs/**
|
||||||
- /webjars/**
|
- /webjars/**
|
||||||
- /**/v3/api-docs/**
|
- /**/v3/api-docs/**
|
||||||
- /api/account/login
|
# Actuator & internal
|
||||||
- /api/account/preLogin
|
|
||||||
- /api/designer/check
|
|
||||||
- /actuator/**
|
- /actuator/**
|
||||||
- /internal/**
|
- /internal/**
|
||||||
- /api/account/sendEmail
|
# Account / Login (only /aida prefix)
|
||||||
- /api/account/noLoginRequired
|
|
||||||
- /api/account/resetPwd
|
|
||||||
- /api/account/designWorksRegister
|
|
||||||
- /api/account/questionnaire
|
|
||||||
- /api/account/schoolLogin
|
|
||||||
- /api/account/enterpriseLogin
|
|
||||||
- /api/account/organizationNameSearch
|
|
||||||
- /api/account/activateNewEmail
|
|
||||||
- /api/python/saveGeneratePicture
|
|
||||||
- /api/python/getLibraryByUserId
|
|
||||||
- /api/python/flush
|
|
||||||
- /api/account/healthy
|
|
||||||
- /api/third/party/**
|
|
||||||
- /api/element/initDefaultSysFile
|
|
||||||
- /api/ali-pay/trade/notify
|
|
||||||
- /api/paypal/ipn/back
|
|
||||||
- /api/alipay-hk/trade/notify
|
|
||||||
- /api/stripe/trade/notify
|
|
||||||
- /api/portfolio/**
|
|
||||||
- /api/global-award/**
|
|
||||||
- /api/llm/stream
|
|
||||||
- /notification/**
|
|
||||||
- /aida/api/account/login
|
- /aida/api/account/login
|
||||||
- /aida/api/account/preLogin
|
- /aida/api/account/preLogin
|
||||||
- /aida/api/designer/check
|
|
||||||
- /aida/api/account/sendEmail
|
- /aida/api/account/sendEmail
|
||||||
- /aida/api/account/noLoginRequired
|
- /aida/api/account/noLoginRequired
|
||||||
- /aida/api/account/resetPwd
|
- /aida/api/account/resetPwd
|
||||||
@@ -106,45 +115,47 @@ gateway:
|
|||||||
- /aida/api/account/enterpriseLogin
|
- /aida/api/account/enterpriseLogin
|
||||||
- /aida/api/account/organizationNameSearch
|
- /aida/api/account/organizationNameSearch
|
||||||
- /aida/api/account/activateNewEmail
|
- /aida/api/account/activateNewEmail
|
||||||
|
- /aida/api/account/healthy
|
||||||
|
- /gateway/healthy
|
||||||
|
# Designer
|
||||||
|
- /aida/api/designer/check
|
||||||
|
# Python (only /aida prefix)
|
||||||
- /aida/api/python/saveGeneratePicture
|
- /aida/api/python/saveGeneratePicture
|
||||||
- /aida/api/python/getLibraryByUserId
|
- /aida/api/python/getLibraryByUserId
|
||||||
- /aida/api/python/flush
|
- /aida/api/python/flush
|
||||||
- /aida/api/account/healthy
|
# Third party (exact paths, only /aida prefix)
|
||||||
- /aida/api/third/party/**
|
- /aida/api/third/party/addUser
|
||||||
|
- /aida/api/third/party/addTrialUser
|
||||||
|
- /aida/api/third/party/editUser
|
||||||
|
- /aida/api/third/party/addNoLoginRequiredNew
|
||||||
|
- /aida/api/third/party/deleteNoLoginRequiredNew
|
||||||
|
- /aida/api/third/party/updateNoLoginRequiredNew
|
||||||
|
- /aida/api/third/party/existNoLoginRequired
|
||||||
|
- /aida/api/third/party/getRedirectUrl
|
||||||
|
- /aida/api/third/party/auth/google_callback
|
||||||
|
- /aida/api/third/party/parseGoogleCredential
|
||||||
|
- /aida/api/third/party/receiveDesignResults
|
||||||
|
- /aida/api/third/party/parseWeChatCode
|
||||||
|
- /aida/api/third/party/receiveDesignParams
|
||||||
|
# Element
|
||||||
- /aida/api/element/initDefaultSysFile
|
- /aida/api/element/initDefaultSysFile
|
||||||
|
# Portfolio (exact paths, only /aida prefix)
|
||||||
|
- /aida/api/portfolio/page
|
||||||
|
- /aida/api/portfolio/detail
|
||||||
|
- /aida/api/portfolio/commentPage
|
||||||
|
- /aida/api/portfolio/viewsIncrease
|
||||||
|
# Global Award
|
||||||
|
- /aida/api/global-award/**
|
||||||
|
# LLM stream
|
||||||
|
- /aida/api/llm/stream
|
||||||
|
# Payment notifications (only /aida prefix)
|
||||||
- /aida/api/ali-pay/trade/notify
|
- /aida/api/ali-pay/trade/notify
|
||||||
- /aida/api/paypal/ipn/back
|
- /aida/api/paypal/ipn/back
|
||||||
- /aida/api/alipay-hk/trade/notify
|
- /aida/api/alipay-hk/trade/notify
|
||||||
- /aida/api/stripe/trade/notify
|
- /aida/api/stripe/trade/notify
|
||||||
- /aida/api/portfolio/**
|
# Notification
|
||||||
- /aida/api/global-award/**
|
- /notification/**
|
||||||
- /aida/api/llm/stream
|
# buyer
|
||||||
- /aida/account/login
|
- /buyer/account/**
|
||||||
- /aida/account/preLogin
|
- /buyer/designer/shop/**
|
||||||
- /aida/designer/check
|
- /buyer/designer/search
|
||||||
- /aida/account/sendEmail
|
|
||||||
- /aida/account/noLoginRequired
|
|
||||||
- /aida/account/resetPwd
|
|
||||||
- /aida/account/designWorksRegister
|
|
||||||
- /aida/account/questionnaire
|
|
||||||
- /aida/account/schoolLogin
|
|
||||||
- /aida/account/enterpriseLogin
|
|
||||||
- /aida/account/organizationNameSearch
|
|
||||||
- /aida/account/activateNewEmail
|
|
||||||
- /aida/python/saveGeneratePicture
|
|
||||||
- /aida/python/getLibraryByUserId
|
|
||||||
- /aida/python/flush
|
|
||||||
- /aida/account/healthy
|
|
||||||
- /aida/third/party/**
|
|
||||||
- /aida/element/initDefaultSysFile
|
|
||||||
- /aida/ali-pay/trade/notify
|
|
||||||
- /aida/paypal/ipn/back
|
|
||||||
- /aida/alipay-hk/trade/notify
|
|
||||||
- /aida/stripe/trade/notify
|
|
||||||
- /aida/portfolio/**
|
|
||||||
- /aida/global-award/**
|
|
||||||
- /aida/llm/stream
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
com.aida.gateway: debug
|
|
||||||
|
|||||||
@@ -4,21 +4,31 @@
|
|||||||
# 示例:docker run -e NACOS_NAMESPACE=prod ...
|
# 示例:docker run -e NACOS_NAMESPACE=prod ...
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
nacos:
|
||||||
|
namespace: dev
|
||||||
|
host: 18.167.251.121:28848
|
||||||
|
username: nacos
|
||||||
|
password: Aidlab123123!
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: aida-gateway
|
name: aida-gateway
|
||||||
config:
|
config:
|
||||||
import: optional:nacos:aida-public-${NACOS_NAMESPACE:test}.yml
|
import: optional:nacos:aida-public-${nacos.namespace}.yml
|
||||||
cloud:
|
cloud:
|
||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
server-addr: ${NACOS_HOST:18.167.251.121:28848}
|
server-addr: ${nacos.host}
|
||||||
namespace: ${NACOS_NAMESPACE:ltx}
|
namespace: ${nacos.namespace}
|
||||||
username: ${NACOS_USERNAME:nacos}
|
username: ${nacos.username}
|
||||||
password: ${NACOS_PASSWORD:Aidlab123123!}
|
password: ${nacos.password}
|
||||||
|
# ip: 18.167.251.121
|
||||||
|
port: 10094
|
||||||
|
# ip-type: ipv4
|
||||||
|
# prefer-ip-address: true
|
||||||
config:
|
config:
|
||||||
server-addr: ${NACOS_HOST:18.167.251.121:28848}
|
server-addr: ${nacos.host}
|
||||||
namespace: ${NACOS_NAMESPACE:ltx}
|
namespace: ${nacos.namespace}
|
||||||
file-extension: yaml
|
file-extension: yaml
|
||||||
username: ${NACOS_USERNAME:nacos}
|
username: ${nacos.username}
|
||||||
password: ${NACOS_PASSWORD:Aidlab123123!}
|
password: ${nacos.password}
|
||||||
|
|||||||
65
src/main/resources/logback-spring.xml
Normal file
65
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||||
|
|
||||||
|
<!-- 日志存放路径 -->
|
||||||
|
<property name="log.path" value="./log" />
|
||||||
|
<!-- 日志输出格式 -->
|
||||||
|
<property name="log.pattern.console" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd 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}}" />
|
||||||
|
<property name="log.pattern.file" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
|
||||||
|
|
||||||
|
<!-- 控制台输出 -->
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern.console}</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- Info 日志文件 -->
|
||||||
|
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${log.path}/aida-gateway-info.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${log.path}/aida-gateway-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>60</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern.file}</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- Error 日志文件 -->
|
||||||
|
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>${log.path}/aida-gateway-error.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<fileNamePattern>${log.path}/aida-gateway-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||||
|
<maxHistory>60</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder>
|
||||||
|
<pattern>${log.pattern.file}</pattern>
|
||||||
|
</encoder>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>ERROR</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 服务模块日志级别控制 -->
|
||||||
|
<logger name="com.aida.gateway" level="debug" />
|
||||||
|
<!-- Spring 日志级别控制 -->
|
||||||
|
<logger name="org.springframework" level="warn" />
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<root level="info">
|
||||||
|
<appender-ref ref="file_info" />
|
||||||
|
<appender-ref ref="file_error" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
Reference in New Issue
Block a user