背景
项目相同的接口想同时提供给外部和内部调用,因为外部调用采用的是签名校验,内部调用采用的是token校验,因为签名校验可以有效起到防止用户多次调用同一个接口的作用,想同一个url,只是域名不同,起到不同的鉴权方式
考虑在网管层实现这一功能。
Spring Cloud Gateway自带的一些断言参数列表
项目中有用到path
- id: openapi
order: 2
uri: ${domain.openapi}
predicates:
- Path=/openapi/**
filters:
- AuthorizationSignature
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
- id: openapiInternal
order: 1
uri: ${domain.openapi}
predicates:
-Path=/openapi/v1/quota/**,/openapi/v1/area/**,/openapi/v1/quotatime/**
filters:
- AuthorizationToken
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
考虑到使用AbstractRoutePredicateFactory工厂类实现一个自定义的路由断言
@Component
public class DomainRoutePredicateFactory extends AbstractRoutePredicateFactory<DomainRoutePredicateFactory.Config> {
public DomainRoutePredicateFactory() {
super(Config.class);
}
private PathMatcher pathMatcher = new AntPathMatcher(".");
public void setPathMatcher(PathMatcher pathMatcher) {
this.pathMatcher = pathMatcher;
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new Predicate<ServerWebExchange>() {
@Override
public boolean test(ServerWebExchange exchange) {
String host = exchange.getRequest().getURI().getHost();
if(StringUtils.isBlank(host)){
return false;
}
Optional<String> optionalPattern = config.getPatterns().stream()
.filter(pattern -> pathMatcher.match(pattern, host)).findFirst();
//检查请求参数中的domain是否与配置的数据相同,如果相同则允许访问,否则不允许访问
// return host.equals(config.getDomain());
if (optionalPattern.isPresent()) {
Map<String, String> variables = pathMatcher
.extractUriTemplateVariables(optionalPattern.get(), host);
ServerWebExchangeUtils.putUriTemplateVariables(exchange, variables);
return true;
}
return false;
}
};
}
/**
* 配置yml文件填写
* predicates:
* - Domain=**.somehost.org,**.anotherhost.org
* 支持多域名配置和模糊匹配
*/
@Validated
public static class Config {
private List<String> patterns = new ArrayList<>();
@Deprecated
public String getPattern() {
if (!CollectionUtils.isEmpty(this.patterns)) {
return patterns.get(0);
}
return null;
}
@Deprecated
public DomainRoutePredicateFactory.Config setPattern(String pattern) {
this.patterns = new ArrayList<>();
this.patterns.add(pattern);
return this;
}
public List<String> getPatterns() {
return patterns;
}
public DomainRoutePredicateFactory.Config setPatterns(List<String> patterns) {
this.patterns = patterns;
return this;
}
@Override
public String toString() {
return new ToStringCreator(this).append("patterns", patterns).toString();
}
}
/**
* 重写 shortcutFieldOrder
* 指定顺序, 此处为内部类接收过滤器参数的属性名
*/
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("patterns");
}
/**
* 重写 shortcutType 方法
*/
@Override
public ShortcutType shortcutType() {
return ShortcutType.GATHER_LIST;
}
}
实现了根据不同域名进行断言,并支持多个域名和模糊域名匹配。
yam文件改为
- id: openapi
order: 2
uri: ${domain.openapi}
predicates:
- Path=/openapi/**
- Domain=gateway-api.**
# - name: Domain
# args:
# patterns: gateway-api.newayz.com,lbi-api.newayz.com
filters:
- AuthorizationSignature
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
- id: openapiInternal
order: 1
uri: ${domain.openapi}
predicates:
- Path=/openapi/v1/quota/**, /openapi/v1/area/**,/openapi/v1/quotatime/**
filters:
- AuthorizationToken
- RewritePath=/openapi/(?<remaining>.*), /${remaining}
两种配置都可以实现根据域名做不同的路由。