This commit is contained in:
2026-04-14 16:27:47 +08:00
commit 4b38a4c952
134 changed files with 7478 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
package com.k12study.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = {"com.k12study.gateway", "com.k12study.common"})
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}

View File

@@ -0,0 +1,75 @@
package com.k12study.gateway.filter;
import com.k12study.common.core.constants.SecurityConstants;
import com.k12study.common.security.config.AuthProperties;
import com.k12study.common.security.jwt.JwtTokenProvider;
import com.k12study.common.security.jwt.JwtUserPrincipal;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class JwtRelayFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final JwtTokenProvider jwtTokenProvider;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
public JwtRelayFilter(AuthProperties authProperties, JwtTokenProvider jwtTokenProvider) {
this.authProperties = authProperties;
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
if (!authProperties.isEnabled() || matches(path, authProperties.getWhitelist())) {
return chain.filter(exchange);
}
String authorization = exchange.getRequest().getHeaders().getFirst(authProperties.getTokenHeader());
if (authorization == null || !authorization.startsWith(authProperties.getTokenPrefix())) {
return unauthorized(exchange, "Missing token");
}
try {
String token = authorization.substring(authProperties.getTokenPrefix().length());
JwtUserPrincipal principal = jwtTokenProvider.parse(token);
var mutatedRequest = exchange.getRequest().mutate()
.header(SecurityConstants.HEADER_USER_ID, principal.userId())
.header(SecurityConstants.HEADER_USERNAME, principal.username())
.header(SecurityConstants.HEADER_DISPLAY_NAME, principal.displayName())
.header(SecurityConstants.HEADER_TENANT_ID, principal.tenantId())
.header(SecurityConstants.HEADER_DEPT_ID, principal.deptId())
.build();
return chain.filter(exchange.mutate().request(mutatedRequest).build());
} catch (Exception exception) {
return unauthorized(exchange, "Invalid token");
}
}
@Override
public int getOrder() {
return -100;
}
private boolean matches(String path, List<String> patterns) {
return patterns.stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
}
private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
byte[] body = ("{\"code\":401,\"message\":\"" + message + "\",\"data\":null}").getBytes();
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
.bufferFactory()
.wrap(body)));
}
}

View File

@@ -0,0 +1,34 @@
server:
port: 8080
spring:
application:
name: k12study-gateway
cloud:
gateway:
routes:
- id: auth
uri: http://localhost:8081
predicates:
- Path=/api/auth/**
filters:
- StripPrefix=1
- id: upms
uri: http://localhost:8082
predicates:
- Path=/api/upms/**
filters:
- StripPrefix=1
management:
endpoints:
web:
exposure:
include: health,info
auth:
enabled: true
whitelist:
- /api/auth/login
- /api/auth/refresh
- /actuator/**