废话
业务多,逻辑复杂的情况下,可能不同的域名过来的请求、不同的路径就需要配置不同的权限校验方式,这种情况的话直接用全局过滤器似乎就不是很方便了。
用这种方式的话确实会比较灵活,但是……老实说业务太复杂了也是配置文件挺大的,条件也多。
所以这里采用了一个专门用来做权限校验的局部过滤器(也可实现其他业务逻辑),搭配nacos动态配置,基本上可以满足业务需求。
缺点,gateway搭配nacos只能是用json的形式(yml理论上也可以,但是需要写的处理逻辑就太多了,麻烦),而nacos中json和yml只能是用一种方式,所以用了json之后,其他的参数就不能很简单的就实现动态配置了。(如果有比较方便的方法,请告诉我)
gateway搭配nacos使用的赘述了,具体翻我之前的文章:Gateway 网关 (一) Nacos 动态配置路由
开搞
如果是直接新建一个原始的局部过滤器GatewayFilter的话,调用的方式有点麻烦,且无法动态变更,所以用GatewayFilterFactory。
大概流程就是定义一个Config参数配置类(可以按需配置,多参数啥的都是可以的),然后重写GatewayFilterFactory类,过滤逻辑就写在重写的这个类里面。
然后在nacos的json配置里面加上对应的配置逻辑就可以生效了
新建一个AuthorizeGatewayFilterFactory类,继承GatewayFilterFactory,并在内部新建一个Config配置类
@Component//切记这个不要漏,漏了这个搞得我出错了半天还怀疑人生
public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthorizeGatewayFilterFactory.Config> {
/**
* 不设防
*/
private static final String AUTH_NOT = "not";
/**
* 静态资源文件
*/
private static final String AUTH_STATIC = "static";
/**
* 网页端
*/
private static final String AUTH_WEB = "web";
/**
* 中台
*/
private static final String AUTH_BACK = "back";
/**
* 埋点
*/
private static final String AUTH_DOT = "dot";
/**
* 客户端接口
*/
private static final String AUTH_API = "api";
/**
* api接口加密
*/
private static final String AUTH_API_EN = "apien";
@Autowired
private StringRedisTemplate stringRedisTemplate;
public AuthorizeGatewayFilterFactory() {
super(Config.class);
ALog.info(LogEnum.CUSTOM_FILTER.getTag(), "Loaded GatewayFilterFactory [Authorize]");
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("type");
}
@Override
public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) {
return (exchange, chain) -> {
if (config.getType().equals(AUTH_API)) {
//api已登录
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap("{\"code\":10011,\"msg\":\"权限校验不通过\"}".getBytes(StandardCharsets.UTF_8));
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return exchange.getResponse().writeWith(Mono.just(buffer));
}
if (config.getType().equals(AUTH_NOT)) {
//不设防
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_API_EN)) {
//API接口加密
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_API_NOT)) {
//API未登录
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_STATIC)) {
//静态资源文件
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_WEB)) {
//网页端
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_BACK)) {
//中台
return chain.filter(exchange);
}
if (config.getType().equals(AUTH_DOT)) {
//埋点
return chain.filter(exchange);
}
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap("{\"code\":10086,\"msg\":\"请配置权限\"}".getBytes(StandardCharsets.UTF_8));
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().add("Content-Type", "application/json;charset=UTF-8");
return exchange.getResponse().writeWith(Mono.just(buffer));
};
}
@Getter
@Setter
public static class Config {
/**
* 过滤类型:not-不设防(正常玩野),web-网页端,api-前端(),api-not-前端未登录,static-静态/资源文件(css样式表等),back-中台,dot-埋点
*/
private String type;
}
nacos配置
[
{
"id":"test-service",//路由id,单条不要重复
"order":10,//优先级,数字越大优先级越低
"predicates":[
{
"args":{
"pattern":"/email/**",
"pattern1":"/ttt/**"
},
"name":"Path"//监听路径
},
{
"args":{
"pattern":"aaa.nnn**",
"pattern1":"ccc.nnn**",
"pattern2":"localhost**"
},
"name":"Host"//指定符合规则的域名
}
],
"filters":[
{
"args":{
"_genkey_0":"1"//转发之后去除一个前缀(按需设置),如/email/test转发之后变成/test
},
"name":"StripPrefix"//去除uri前缀
},
{
"args":{
"_genkey_0":"/api"
},
"name":"PrefixPath"//转发之后新增前缀,如/test转发之后变成/api/test
},
{
"args":{
"type":"api"//过滤器里面congif类的值,type跟config里面的字段名称一致,如果有多个配置就写在这里
},
"name":"Authorize"//自定义过滤器AuthorizeGatewayFilterFactory(根据类名去掉GatewayFilterFactory的值,无需配置)
}
],
"uri":"http://192.168.2.200:10201/"//转发之后路径
}
]
依照上面的规则(前提是中间的权限校验能过)
转发之前的路径:
http://localhost:10100/email/aaa
转发之后的路径:
http://192.168.2.200:10201/api/aaa