Compare commits
3 Commits
1c04b32544
...
f7e87fe84c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7e87fe84c | ||
|
|
5284bfa813 | ||
|
|
218bed1813 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
/.idea/
|
/.idea/
|
||||||
|
/target/
|
||||||
|
|||||||
19
pom.xml
19
pom.xml
@@ -99,6 +99,25 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Knife4j Gateway Aggregation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-gateway-spring-boot-starter</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.xiaoymin</groupId>
|
||||||
|
<artifactId>knife4j-openapi3-ui</artifactId>
|
||||||
|
<version>4.4.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Cloud LoadBalancer -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import reactor.core.publisher.Mono;
|
|||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,6 +47,7 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
@Qualifier("reactiveRedisTemplate")
|
@Qualifier("reactiveRedisTemplate")
|
||||||
private final ReactiveRedisTemplate<String, String> redisTemplate;
|
private final ReactiveRedisTemplate<String, String> redisTemplate;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||||
@@ -93,12 +95,21 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
// 5. 黑名单检查(仅当启用时)
|
// 5. 黑名单检查(仅当启用时)
|
||||||
if (authProperties.isBlacklistEnabled()) {
|
if (authProperties.isBlacklistEnabled()) {
|
||||||
String blacklistKey = AuthConstants.BLACKLIST_PREFIX + principal.getId();
|
String blacklistKey = AuthConstants.BLACKLIST_PREFIX + principal.getId();
|
||||||
Boolean isBlacklisted = redisTemplate.hasKey(blacklistKey).block();
|
return redisTemplate.hasKey(blacklistKey).flatMap(isBlacklisted -> {
|
||||||
if (Boolean.TRUE.equals(isBlacklisted)) {
|
if (Boolean.TRUE.equals(isBlacklisted)) {
|
||||||
return writeUnauthorized(exchange, AuthConstants.MSG_TOKEN_BLACKLISTED);
|
return writeUnauthorized(exchange, AuthConstants.MSG_TOKEN_BLACKLISTED);
|
||||||
}
|
}
|
||||||
|
return continueChain(exchange, chain, principal);
|
||||||
|
}).onErrorResume(e -> {
|
||||||
|
log.error("Redis check failed", e);
|
||||||
|
return continueChain(exchange, chain, principal);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return continueChain(exchange, chain, principal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<Void> continueChain(ServerWebExchange exchange, WebFilterChain chain, AuthPrincipalVo principal) {
|
||||||
// 6. 写入下游请求头
|
// 6. 写入下游请求头
|
||||||
String userInfoJson;
|
String userInfoJson;
|
||||||
try {
|
try {
|
||||||
@@ -121,27 +132,13 @@ public class GlobalAuthWebFilter implements WebFilter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (String pattern : authProperties.getIgnorePaths()) {
|
for (String pattern : authProperties.getIgnorePaths()) {
|
||||||
if (matches(pattern, requestUri)) {
|
if (pathMatcher.match(pattern, requestUri)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matches(String pattern, String uri) {
|
|
||||||
if (pattern.endsWith("/**")) {
|
|
||||||
String prefix = pattern.substring(0, pattern.length() - 3);
|
|
||||||
return uri.startsWith(prefix);
|
|
||||||
}
|
|
||||||
if (pattern.endsWith("/*")) {
|
|
||||||
String prefix = pattern.substring(0, pattern.length() - 2);
|
|
||||||
if (!uri.startsWith(prefix)) return false;
|
|
||||||
String suffix = uri.substring(prefix.length());
|
|
||||||
return !suffix.contains("/");
|
|
||||||
}
|
|
||||||
return uri.contains(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Claims parseToken(String token) {
|
private Claims parseToken(String token) {
|
||||||
SecretKey key = buildSigningKey();
|
SecretKey key = buildSigningKey();
|
||||||
return Jwts.parser()
|
return Jwts.parser()
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package com.aida.gateway.route;
|
|
||||||
|
|
||||||
import org.springframework.cloud.gateway.route.RouteLocator;
|
|
||||||
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 路由配置。
|
|
||||||
* <p>
|
|
||||||
* 注意:实际生产环境中建议将路由配置放在 Nacos 配置中心。
|
|
||||||
* StripPrefix=1 将 /seller 前缀剥离,例如:
|
|
||||||
* /seller/designer/check -> /designer/check (发到 aida-seller 的 /api/designer/check)
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class RouteConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
|
|
||||||
return builder.routes()
|
|
||||||
// /internal/** 用于内部服务调用(如 logout 黑名单),不需要 stripPrefix
|
|
||||||
.route("aida-gateway-internal", r -> r
|
|
||||||
.path("/internal/**")
|
|
||||||
.uri("forward:/internal"))
|
|
||||||
// aida-seller 服务
|
|
||||||
.route("aida-seller", r -> r
|
|
||||||
.path("/seller/**")
|
|
||||||
.filters(f -> f.stripPrefix(1))
|
|
||||||
.uri("lb://aida-seller"))
|
|
||||||
// aida-back_001 服务
|
|
||||||
.route("aida-back", r -> r
|
|
||||||
.path("/api/**")
|
|
||||||
.filters(f -> f.stripPrefix(1))
|
|
||||||
.uri("lb://aida-back"))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,11 +9,47 @@ server:
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: aida-gateway
|
name: aida-gateway
|
||||||
|
cloud:
|
||||||
|
gateway:
|
||||||
|
routes:
|
||||||
|
- id: aida-back
|
||||||
|
uri: lb://aida-back
|
||||||
|
predicates:
|
||||||
|
- Path=/aida/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- id: aida-seller
|
||||||
|
uri: lb://aida-seller
|
||||||
|
predicates:
|
||||||
|
- Path=/seller/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
|
- id: aida-python
|
||||||
|
uri: http://18.167.251.121:9994
|
||||||
|
predicates:
|
||||||
|
- Path=/python/**
|
||||||
|
# ---------- Knife4j 网关聚合配置 ----------
|
||||||
|
knife4j:
|
||||||
|
gateway:
|
||||||
|
enabled: true
|
||||||
|
# 手动指定下游服务的文档聚合,可以灵活应对不同服务的 API 版本或路径前缀
|
||||||
|
strategy: manual
|
||||||
|
routes:
|
||||||
|
- name: aida主服务
|
||||||
|
url: /aida/v3/api-docs
|
||||||
|
service-name: aida-back
|
||||||
|
context-path: /aida
|
||||||
|
order: 1
|
||||||
|
- name: 商家端服务 (Seller)
|
||||||
|
url: /seller/v3/api-docs
|
||||||
|
service-name: aida-seller
|
||||||
|
context-path: /seller
|
||||||
|
order: 2
|
||||||
|
|
||||||
# ---------- Gateway JWT 认证(gateway 独有) ----------
|
# ---------- Gateway JWT 认证(gateway 独有) ----------
|
||||||
gateway:
|
gateway:
|
||||||
auth:
|
auth:
|
||||||
jwt-secret: ${BACK_JWT_SECRET:JWTSECRET}
|
jwt-secret: JWTSECRET
|
||||||
jwt-token-header: Authorization
|
jwt-token-header: Authorization
|
||||||
jwt-token-prefix: Bearer-
|
jwt-token-prefix: Bearer-
|
||||||
blacklist-enabled: true
|
blacklist-enabled: true
|
||||||
@@ -21,11 +57,15 @@ gateway:
|
|||||||
- /favicon.ico
|
- /favicon.ico
|
||||||
- /doc.html
|
- /doc.html
|
||||||
- /swagger-ui.html
|
- /swagger-ui.html
|
||||||
|
- /swagger-ui
|
||||||
- /swagger-ui/**
|
- /swagger-ui/**
|
||||||
- /swagger-resources/**
|
- /swagger-resources/**
|
||||||
- /v2/api-docs
|
- /v2/api-docs
|
||||||
|
- /v2/api-docs/**
|
||||||
|
- /v3/api-docs
|
||||||
- /v3/api-docs/**
|
- /v3/api-docs/**
|
||||||
- /webjars/**
|
- /webjars/**
|
||||||
|
- /**/v3/api-docs/**
|
||||||
- /api/account/login
|
- /api/account/login
|
||||||
- /api/account/preLogin
|
- /api/account/preLogin
|
||||||
- /api/designer/check
|
- /api/designer/check
|
||||||
@@ -54,6 +94,56 @@ gateway:
|
|||||||
- /api/global-award/**
|
- /api/global-award/**
|
||||||
- /api/llm/stream
|
- /api/llm/stream
|
||||||
- /notification/**
|
- /notification/**
|
||||||
|
- /aida/api/account/login
|
||||||
|
- /aida/api/account/preLogin
|
||||||
|
- /aida/api/designer/check
|
||||||
|
- /aida/api/account/sendEmail
|
||||||
|
- /aida/api/account/noLoginRequired
|
||||||
|
- /aida/api/account/resetPwd
|
||||||
|
- /aida/api/account/designWorksRegister
|
||||||
|
- /aida/api/account/questionnaire
|
||||||
|
- /aida/api/account/schoolLogin
|
||||||
|
- /aida/api/account/enterpriseLogin
|
||||||
|
- /aida/api/account/organizationNameSearch
|
||||||
|
- /aida/api/account/activateNewEmail
|
||||||
|
- /aida/api/python/saveGeneratePicture
|
||||||
|
- /aida/api/python/getLibraryByUserId
|
||||||
|
- /aida/api/python/flush
|
||||||
|
- /aida/api/account/healthy
|
||||||
|
- /aida/api/third/party/**
|
||||||
|
- /aida/api/element/initDefaultSysFile
|
||||||
|
- /aida/api/ali-pay/trade/notify
|
||||||
|
- /aida/api/paypal/ipn/back
|
||||||
|
- /aida/api/alipay-hk/trade/notify
|
||||||
|
- /aida/api/stripe/trade/notify
|
||||||
|
- /aida/api/portfolio/**
|
||||||
|
- /aida/api/global-award/**
|
||||||
|
- /aida/api/llm/stream
|
||||||
|
- /aida/account/login
|
||||||
|
- /aida/account/preLogin
|
||||||
|
- /aida/designer/check
|
||||||
|
- /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:
|
logging:
|
||||||
level:
|
level:
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: aida-gateway
|
name: aida-gateway
|
||||||
config:
|
config:
|
||||||
import: optional:nacos:aida-public-${NACOS_NAMESPACE:dev}.yml
|
import: optional:nacos:aida-public-${NACOS_NAMESPACE:test}.yml
|
||||||
cloud:
|
cloud:
|
||||||
nacos:
|
nacos:
|
||||||
discovery:
|
discovery:
|
||||||
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
||||||
namespace: ${NACOS_NAMESPACE:dev}
|
namespace: ${NACOS_NAMESPACE:test}
|
||||||
config:
|
config:
|
||||||
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
server-addr: ${NACOS_HOST:127.0.0.1:8848}
|
||||||
namespace: ${NACOS_NAMESPACE:dev}
|
namespace: ${NACOS_NAMESPACE:test}
|
||||||
file-extension: yaml
|
file-extension: yaml
|
||||||
|
|||||||
Reference in New Issue
Block a user