Skip to content

4. 安全&拦截

fancie edited this page Feb 6, 2022 · 4 revisions

项目运行起来之后怎么防止非法用户访问我们的资源,这里一般分为内网资源和公网资源

  • 1.内网资源

内网资源只能由内网机器或者服务访问,我们一般可以在资源上添加过滤器,过滤掉外网ip地址,或者访问的时候携带某个key,然后验证key的有效性,有效则放行

添加过滤器的方式我就不在这里讲了,本文档主要讲的是服务A通过openfeign的方式调用服务B,网站怎么知道服务A有权限

项目中采用的方案比较简单,直接在配置文件配置token,让请求的header携带这个token,网关的过滤器验证token的合法性

1.1 在feign的参数里面“defaultRequestHeaders”新增一个authToken

feign:
  client:
    config:
      default:
        connectTimeout: 6000000  # 相当于Request.Options
        readTimeout: 6000000     # 相当于Request.Options
        defaultRequestHeaders:
          authToken: EbDcwcLG3zfGdiHFFzSQbbf4Y1epwOK14wRGvqt8BmYbW0FpWKY

1.2 网关过滤器验证authToken的合法性

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = exchange.getRequest();
    String path = request.getPath().toString();
    var authToken = request.getHeaders().get("authToken");
    if(Contants.isInOpenFeignServices(path)){
        if(authToken != null && authToken.size() > 0 && Contants.openFeignAuthToken.equals(authToken.get(0))){
            //放行
            return chain.filter(exchange);
        }
        //拒绝
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.NOT_ACCEPTABLE); //这个状态码是406
        return exchange.getResponse().setComplete();
    }
    //其它是web服务,都放行,交给其它过滤器继续过滤
    return chain.filter(exchange);
}

这个方式有一个弊端,authToken是永久有效的,下一步需要用auth2的方式申请token

1.3 控制feign接口的访问路径

例如:web可以访问server1和server2,server1不能访问server2,但是server2不能访问server1(这个可以在网关层调整)

第一步:RequestTemplate增加相应的header

@Override
public void apply(RequestTemplate template) {
    // 携带token到Feign的服务端
    template.getRequestVariables();
    template.header("Authorization", "chainTokenValue");
    //在网关层用来控制资源访问路径,比如:web可以访问server1和server2,但是server2不能访问server1(这个可以在网关层调整)
    template.header("ApplicationName", applicationName);
}

第二步:网关层过滤

var applicationNameHeader = request.getHeaders().get("ApplicationName");
String applicationName = applicationNameHeader != null && applicationNameHeader.size() > 0 ? applicationNameHeader.get(0) : "";
boolean appHasRight = Contants.havaRight(applicationName, path);
if(appHasRight){
    //放行
    return chain.filter(exchange);
}
  • 2.公网资源

公网资源需要阻止某些非法用户、爬虫等对服务器资源的占用或者执行非法资源

我的思路是这样的:在数据库配置相应规则,例如某个ip,或者useragent携带某个参数,网关过滤器读取配置,然后验证相应的规则,如果包含在规则里面就阻止通过,以下是过滤器相关代码:

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    log.info("ServerGatewayFilter filter ");
    HttpHeaders headers = exchange.getRequest().getHeaders();
    String userAgent = headers.get("User-Agent").toString();
    if(userAgent.indexOf("spider") < 0){
        return chain.filter(exchange); // 放行
    }
    return null;
}

过滤器比较简单,仅仅读取User-Agent是否包含spider。


有没发现filter跟我们常见的不一样,它的返回值是Mono<Void>类型,这是因为gateway采用的WebFlux,WebFlux是一个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现。

((*以上内容代码只贴了部分,全部代码都在项目中*))

Clone this wiki locally