- 添加相关配置
- 添加过滤器,路由管理器配置,针对路由进行鉴权、服务转发
添加相关配置
pom.xml文件添加mvn包
<!-- SpringCloud Alibaba Nacos 服务注册 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos 配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- spring gateway 网关 -->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
bootstrap.yml添加配置
server:
port: 8080
spring:
application:
name: gateway
profiles:
active: dev
cloud:
nacos:
discovery: # 服务注册、发现
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
service: ${spring.application.name}-${spring.profiles.active}
config:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
file-extension: yml
shared-configs: # 指定额外的配置文件
- data-id: application.yml
loadbalancer:
nacos:
enabled: true # 开启nacos负载均衡策略
gateway:
routes: # 网关路由配置
- id: auth-service # 路由id,自定义,只要唯一即可
#uri: http://127.0.0.1:8088 # 路由的目标地址 http就是固定地址
uri: lb://auth-${spring.profiles.active} # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/auth/** # 这个是按照路径匹配,只要以 /auth/ 开头就符合要求
filters: # 路由过滤器,对请求或者响应做出处理
- StripPrefix=1 # 去掉路径一条前缀,这里是: /auth
metadata:
auth-white-list: # 过滤器白名单列表,目前只配置login路由白名单
- /login/**
此时启动gateway、auth服务,访问http://127.0.0.1:8080/auth/login服务就会自动转发到http://auth-dev/login,auth-dev就是Nacos注册的鉴权服务。
auth服务路由代码可以参考这篇文章最后一段Controller代码: https://halo.ljdzsk.com/archives/springbootswagger3-tong-yi-jie-kou-xiang-ying
添加过滤器,路由管理器配置,针对路由进行鉴权、服务转发
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
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.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
@Slf4j
@Component
@RequiredArgsConstructor
public class AuthFilter implements GlobalFilter {
private final RouteMetadataService routeMetadataService;
private final ObjectMapper objectMapper; // JSON 序列化工具
private final PathMatcher pathMatcher = new AntPathMatcher(); // Spring内置的路径匹配器
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("开始鉴权");
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
if (route != null) {
// 过滤白名单路由鉴权
List<String> authWhiteList = routeMetadataService.getauthWhiteList(route.getId());
String path = exchange.getRequest().getURI().getPath();
if (authWhiteList.stream().anyMatch(pattern -> pathMatcher.match(pattern, path))) {
return chain.filter(exchange);
}
}
// 从请求头或参数中获取Token
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
// 验证Token逻辑(如调用Auth服务)
if (!isValidToken(token)) {
return Result.error(HttpStatus.UNAUTHORIZED).toMono(exchange.getResponse(), objectMapper);
}
return chain.filter(exchange);
}
/***
* 鉴权判断
*/
private boolean isValidToken(String token) {
return false;
}
}
路由管理服务
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/***
* 路由管理
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class RouteMetadataService {
private final RouteLocator routeLocator;
private final Map<String, List<String>> routeExcludePaths = new HashMap<>();
/**
* 加载所有路由的元数据
*/
public void loadMetadata() {
Flux<Route> routes = routeLocator.getRoutes();
routes.subscribe(route -> {
// 从元数据获取鉴权白名单,路径在白名单中,无需鉴权
List<String> authWhiteList = Optional.ofNullable(route.getMetadata().get("auth-white-list"))
.map(obj -> {
if (obj instanceof List) {
// 直接转换为List<String>
return (List<String>) obj;
} else if (obj instanceof Map) {
// 如果是Map,提取所有值组成List
Map<?, ?> map = (Map<?, ?>) obj;
return map.values().stream()
.filter(String.class::isInstance)
.map(String.class::cast)
.collect(Collectors.toList());
} else {
log.warn("auth-white-list 类型不匹配: {}", obj.getClass().getName());
return List.<String>of();
}
})
.orElse(List.of()); // 默认返回空列表
routeExcludePaths.put(route.getId(), authWhiteList);
});
}
/**
* 获取指定路由的白名单路径列表
*/
public List<String> getauthWhiteList(String routeId) {
return routeExcludePaths.getOrDefault(routeId, List.of());
}
/**
* 动态路由更新时调用此方法刷新缓存
*/
@PostConstruct
public void refreshMetadata() {
routeExcludePaths.clear();
loadMetadata();
}
}
此时启动gateway、auth服务,访问:http://127.0.0.1:8080/auth/login可以正常转发,http://127.0.0.1:8080/auth/login1 会提示没有权限。