让微服务只允许来自网关的请求
一般各个微服务的请求都是通过网关转发的,但是想要让微服务只允许来自网关的请求:
实际在生产项目,微服务和网关之间都是走内网调用的,并不会通过公网IP,因此外部机器直接访问公网IP是用会被防火墙屏蔽,微服务这时候和网关之间的请求也就是安全的;对外提供服务的域名会走 NGINX反向代理到网关,网关转发到对应的服务,真正对外提供的仅有NGINX。
要是你的服务器是不同厂商服务器,没有内网可以调用,也可以通过固定端口开放的形式,使用公网ip提供。
比如有网关所在服务器公网ip和端口: 192.168.0.1:8080
微服务1所在服务器公网ip和端口: 192.168.0.2:8080
假定都是公网ip,并且没有内网,因此微服务网关可以对192.168.0.2的8080端口开放,
微服务对网关的192.168.0.1:8080开放,就可以组成互通的环境了。
这里以阿里云举例:
当然,如果现在没有这种内网、防火墙环境,也可以使用临时方案替代。
假设使用了SpringCloud的Feign调用,那其实还是走的http,可以在请求头中加入token,使用过滤器的方式
在网关中:
添加一个参数systemFrom,值为gateway,一起转发给微服务,微服务只需要判断值是不是gateway即可
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//...
//省略鉴别token的代码
//只允许通过网关访问
ServerHttpRequest req = exchange.getRequest().mutate()
.header("systemFrom", "gateway").build();
return chain.filter(exchange.mutate().request(req.mutate().build()).build());
}
@Override
public int getOrder() {
return 0;
}
}
在微服务中做拦截,判断systemFrom的值是不是gateway:
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果不是网关来的服务,都拒绝访问
String fromKey = request.getHeader("systemFrom");
if(fromKey == null || !"".equals("gateway")){
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
response.setStatus(401); //权限不足
writer.write("error");
return false;
}
//... 鉴权Token
return true;
}
}
这里的systemFrom的key和value值是临时演示的,可以增加一套新的加密解密算法
这样每次请求中都会校验是不是网关带来的参数。
当然实际生产还是推荐第一种方案。