diff --git a/pom.xml b/pom.xml index 3e6c2a0..0bc789d 100644 --- a/pom.xml +++ b/pom.xml @@ -21,9 +21,87 @@ 1.0-SNAPSHOT - 17 - 17 - UTF-8 + 17 + 2.7.18 + 2021.0.8 + 2021.1 + + + + org.springframework.cloud + spring-cloud-starter-gateway + 3.1.8 + + + + + org.springframework.boot + spring-boot-starter-webflux + ${spring.boot.version} + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + ${spring.cloud.alibaba.version} + + + + + org.springframework.boot + spring-boot-starter-actuator + ${spring.boot.version} + + + + + org.projectlombok + lombok + 1.18.30 + provided + + + + org.springframework.cloud + spring-cloud-starter-loadbalancer + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + + repackage + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + ${java.version} + ${java.version} + + + + + \ No newline at end of file diff --git a/xs-server/pom.xml b/xs-server/pom.xml index 9f93468..b5c4153 100644 --- a/xs-server/pom.xml +++ b/xs-server/pom.xml @@ -17,4 +17,12 @@ UTF-8 + + + com.xiang + xs-service + 1.0-SNAPSHOT + + + \ No newline at end of file diff --git a/xs-server/src/main/java/com/xiang/XsGatewayApplication.java b/xs-server/src/main/java/com/xiang/XsGatewayApplication.java index d230ca3..a0a5692 100644 --- a/xs-server/src/main/java/com/xiang/XsGatewayApplication.java +++ b/xs-server/src/main/java/com/xiang/XsGatewayApplication.java @@ -2,12 +2,14 @@ package com.xiang; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; /** * @Author: xiang * @Date: 2025-08-12 17:26 */ -@SpringBootApplication +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) public class XsGatewayApplication { public static void main(String[] args) { SpringApplication.run(XsGatewayApplication.class, args); diff --git a/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java b/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java new file mode 100644 index 0000000..9499738 --- /dev/null +++ b/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java @@ -0,0 +1,30 @@ +package com.xiang.xservice.gateway.server.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class ServiceDiscoveryController { + @Autowired + private DiscoveryClient discoveryClient; + + /** + * 查看所有注册到 Nacos 的服务 + */ + @GetMapping("/services") + public List getServices() { + return discoveryClient.getServices(); + } + + /** + * 查看某个服务的实例信息 + */ + @GetMapping("/services/instances") + public Object getServiceInstances(String serviceName) { + return discoveryClient.getInstances(serviceName); + } +} diff --git a/xs-server/src/main/resources/application-local.yml b/xs-server/src/main/resources/application-local.yml index e69de29..d061a5c 100644 --- a/xs-server/src/main/resources/application-local.yml +++ b/xs-server/src/main/resources/application-local.yml @@ -0,0 +1,40 @@ +server: + port: 38010 + +spring: + application: + name: xservice-gateway + main: + web-application-type: reactive # 强制使用 WebFlux + cloud: + nacos: + discovery: + server-addr: general.xiangtech.xyz:8848 + namespace: 00131110-3ecb-4a35-8bbb-624edde1d937 + group: DEFAULT_GROUP + username: nacos + password: nacos + gateway: + discovery: + locator: + enabled: true # 开启 nacos 自动路由 + routes: + - id: xservice-auth-center + uri: lb://xservice-auth-center + predicates: + - Path=/api-auth/** + filters: + - StripPrefix=1 + + redis: + host: r-bp1wt59a6nfyt4e3ltpd.redis.rds.aliyuncs.com + port: 6379 + password: Xiang0000 # 如果无密码可以省略 + database: 0 + timeout: 5000 + lettuce: + pool: + max-active: 8 + max-idle: 8 + min-idle: 0 + max-wait: 1000 \ No newline at end of file diff --git a/xs-server/src/main/resources/application.yml b/xs-server/src/main/resources/application.yml index 8258c24..2ad80be 100644 --- a/xs-server/src/main/resources/application.yml +++ b/xs-server/src/main/resources/application.yml @@ -3,4 +3,6 @@ server: spring: profiles: - active: local \ No newline at end of file + active: local + main: + web-application-type: reactive \ No newline at end of file diff --git a/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java new file mode 100644 index 0000000..92ed0c2 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java @@ -0,0 +1,59 @@ +package com.xiang.xservice.gateway.service.core; + +import lombok.extern.slf4j.Slf4j; +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.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +@Slf4j +@Component +public class AuthGlobalFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + String path = request.getURI().getPath(); + // 放行 /public/** 和 /login + if (path.contains("/public/") || path.contains("/login")) { + log.debug("跳过 Token 校验: {}", path); + return chain.filter(exchange); + } + + // 获取 Header 中的 Authorization + String token = request.getHeaders().getFirst("Authorization"); + + if (!StringUtils.hasText(token)) { + log.warn("❌ 缺少 Token: {}", path); + exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + return exchange.getResponse().setComplete(); + } + + try { + // TODO: 这里换成你自己的 JwtUtil.verify(token) +// boolean valid = JwtUtil.verify(token); + if (false) { + log.warn("❌ Token 校验失败: {}", token); + exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + return exchange.getResponse().setComplete(); + } + } catch (Exception e) { + log.error("❌ Token 校验异常", e); + exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + return exchange.getResponse().setComplete(); + } + + log.info("✅ Token 校验通过: {}", token); + return chain.filter(exchange); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java new file mode 100644 index 0000000..decedc7 --- /dev/null +++ b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java @@ -0,0 +1,42 @@ +package com.xiang.xservice.gateway.service.core; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.Ordered; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import java.net.InetSocketAddress; + +@Slf4j +@Component +public class LoggerGlobalFilter implements GlobalFilter, Ordered { + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + log.info("🌐 Gateway 请求进入, 原始请求路径:{}", exchange.getRequest().getURI().getPath()); + ServerHttpRequest request = exchange.getRequest(); + InetSocketAddress remoteAddress = request.getRemoteAddress(); + log.info("请求路径: {} | 方法: {} | 来源: {} | 匹配到路由:{}, 转发目标地址:{}", + request.getURI(), + request.getMethod(), + remoteAddress != null ? remoteAddress.getHostString() : "unknown", + exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR), + exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR)); + + // 继续执行过滤链 + return chain.filter(exchange) + .then(Mono.fromRunnable(() -> { + log.info("响应状态: {}", exchange.getResponse().getStatusCode()); + })); + } + + @Override + public int getOrder() { + return 0; + } +}