Compare commits
11 Commits
9124256f01
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0eb6426a99 | ||
|
|
743b2bbda9 | ||
|
|
9fc17d2940 | ||
|
|
41bb344e97 | ||
|
|
cddd74db2a | ||
|
|
69dba26b73 | ||
|
|
206431ccb0 | ||
| 62f8219d30 | |||
|
|
2daec6b123 | ||
|
|
7e19ba4d06 | ||
|
|
58951ff9b6 |
@@ -50,7 +50,7 @@ jobs:
|
||||
VOLUME /tmp
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||
RUN echo 'Asia/Shanghai' > /etc/timezone
|
||||
ADD ./*.jar /app.jar
|
||||
ADD ./target/*.jar /app.jar
|
||||
ENTRYPOINT ["java","-jar","/app.jar"]
|
||||
EOF
|
||||
echo "Dockerfile内容:"
|
||||
|
||||
10
pom.xml
10
pom.xml
@@ -62,17 +62,11 @@
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Hutool (aligned with aida_seller 5.8.26) -->
|
||||
<!-- Hutool -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.26</version>
|
||||
<version>5.8.23</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis (for token blacklist) -->
|
||||
|
||||
@@ -19,5 +19,13 @@ public class GatewayAuthProperties {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -65,24 +65,43 @@ public class GlobalAuthWebFilter implements WebFilter, Ordered {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
// 2. 白名单直接放行
|
||||
// 2. 白名单直接放行(完全跳过认证)
|
||||
if (isIgnoredPath(path)) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
// 3. 提取 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()
|
||||
.getFirst(authProperties.getJwtTokenHeader());
|
||||
if (StrUtil.isBlank(rawHeader)) {
|
||||
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;
|
||||
if (rawHeader.startsWith(authProperties.getJwtTokenPrefix())) {
|
||||
token = rawHeader.substring(authProperties.getJwtTokenPrefix().length());
|
||||
}
|
||||
|
||||
// 4. JWT 签名验证
|
||||
// JWT 签名验证
|
||||
Claims claims;
|
||||
try {
|
||||
claims = parseToken(token);
|
||||
@@ -91,7 +110,7 @@ public class GlobalAuthWebFilter implements WebFilter, Ordered {
|
||||
return writeUnauthorized(exchange, AuthConstants.MSG_TOKEN_EXPIRED);
|
||||
}
|
||||
|
||||
// 5. 解析用户信息
|
||||
// 解析用户信息
|
||||
AuthPrincipalVo principal;
|
||||
try {
|
||||
principal = objectMapper.readValue(claims.getSubject(), AuthPrincipalVo.class);
|
||||
@@ -104,7 +123,7 @@ public class GlobalAuthWebFilter implements WebFilter, Ordered {
|
||||
return writeUnauthorized(exchange, AuthConstants.MSG_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
// 6. 黑名单检查(仅当启用时)
|
||||
// 黑名单检查
|
||||
if (authProperties.isBlacklistEnabled()) {
|
||||
String blacklistKey = AuthConstants.BLACKLIST_PREFIX + principal.getId();
|
||||
return redisTemplate.hasKey(blacklistKey).flatMap(isBlacklisted -> {
|
||||
@@ -151,6 +170,18 @@ public class GlobalAuthWebFilter implements WebFilter, Ordered {
|
||||
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) {
|
||||
SecretKey key = buildSigningKey();
|
||||
return Jwts.parser()
|
||||
|
||||
@@ -50,6 +50,12 @@ spring:
|
||||
uri: http://18.167.251.121:9994
|
||||
predicates:
|
||||
- Path=/python/**
|
||||
- id: aida-buyer
|
||||
uri: lb://aida-buyer
|
||||
predicates:
|
||||
- Path=/buyer/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
# ---------- Knife4j 网关聚合配置 ----------
|
||||
knife4j:
|
||||
gateway:
|
||||
@@ -67,6 +73,11 @@ knife4j:
|
||||
service-name: aida-seller
|
||||
context-path: /seller
|
||||
order: 2
|
||||
- name: 买家端服务 (Buyer)
|
||||
url: /buyer/v3/api-docs
|
||||
service-name: aida-buyer
|
||||
context-path: /buyer
|
||||
order: 3
|
||||
|
||||
# ---------- Gateway JWT 认证(gateway 独有) ----------
|
||||
gateway:
|
||||
@@ -144,5 +155,7 @@ gateway:
|
||||
- /aida/api/stripe/trade/notify
|
||||
# Notification
|
||||
- /notification/**
|
||||
|
||||
logging:
|
||||
# buyer
|
||||
- /buyer/account/**
|
||||
- /buyer/designer/shop/**
|
||||
- /buyer/designer/search
|
||||
|
||||
Reference in New Issue
Block a user