不允许直接调用微服务。只允许通过 API 网关

Don't allow direct calls to Microservices. Only allow through API Gateway

也许这是一个奇怪的问题(我是微服务新手)。但是我正在寻找有关如何进行此操作的一些信息。不需要 Spring 具体,但这是我目前使用的框架。

示例: 假设我们有两个微服务

a) http://myurlfortesting.com:8085/api/rest/serviceone

b) http://myurlfortesting.com:8090/api/rest/servicetwo

并且我们设置了 Spring Zuul(充当 API 网关),并使用以下转发来电的规则:

/rest/one -> http://myurlfortesting.com:8085/api/rest/serviceone

/rest/two -> http://myurlfortesting.com:8090/api/rest/servicetwo

问题... 有没有办法阻止用户直接访问 A 和 B 中提到的服务(只允许通过 API 网关的服务)?

可以通过 Springs Zuul(充当 API 网关)通过设置一些额外的过滤器来完成,还是我们在微服务端点中设置它?

甚至想知道是否有办法甚至不处理不通过 API 网关的微服务端点上的直接调用。

也许这是通过服务器特定规则解决的,与 Spring 无关?

非常感谢,

/D

假设您有防火墙,您可以将到服务器的入站流量限制在您的 Zuul 端点公开的端口,并禁止任何人直接访问微服务的端口。

如果你想避免走防火墙路线,你可以强制端点检查特定的 HTTP header 或 Zuul 在转发请求之前设置的东西,但这会很麻烦容易规避。根据我过去的经验,"right" 方法是通过防火墙执行此操作。您的应用程序应负责处理请求。您的防火墙应该负责决定谁可以访问特定端点。

一般来说,这种情况是通过实施适当的 OAuth 服务器来处理的,其中只有您的 API 网关会处理令牌验证。任何对微服务的直接调用都不会进行适当的令牌交换,因此请求将被中止。

如果您已经在任何云上部署了微服务,那么您可以通过仅将路由公开给 API 网关来实现这一点。 是的,防火墙阻止、IP 白名单是限制对微服务访问的其他一些方法。

使用 AWS API 网关执行此操作的正确方法是使用最近启动的 'VPC Link' 集成,它可以保护 API 网关与您的 VPC 后端之间的连接。

https://aws.amazon.com/about-aws/whats-new/2017/11/amazon-api-gateway-supports-endpoint-integrations-with-private-vpcs/

使用反向代理。我们出于相同的目的使用 Nginx。 Api 网关应始终部署在生产场景的负载均衡器后面,以避免网关成为单点故障。此外,网关和服务部署在 VPC 中。

嘿,我终于找到了一个解决方案,通过使用微服务架构,只接受来自 API 网关的请求,为此你可以创建一个过滤器,像 Zuul 一样充当代理,检查 header 'X-Forwarded-Host',如果它与网关服务不匹配,则 return 一个未经授权的异常。

public class CustomGatewayFilter extends GenericFilterBean {

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
        throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) resp;

    String proxyForwardedHostHeader = request.getHeader("X-Forwarded-Host");

    if (proxyForwardedHostHeader == null || !proxyForwardedHostHeader.equals(GatewayConstant.getGatewayURL())) {
        UnauthorisedException unauthorisedException = new UnauthorisedException("Unauthorized Access",
                "Unauthorized Access, you should pass through the API gateway");
        byte[] responseToSend = restResponseBytes(unauthorisedException.getErrorResponse());
        ((HttpServletResponse) response).setHeader("Content-Type", "application/json");
        ((HttpServletResponse) response).setStatus(401);
        response.getOutputStream().write(responseToSend);
        return;
    }
    chain.doFilter(request, response);
}

private byte[] restResponseBytes(ErrorResponse errorResponse) throws IOException {
    String serialized = new ObjectMapper().writeValueAsString(errorResponse);
    return serialized.getBytes();
}

}

不要忘记在 SpringSecurity 配置中添加自定义过滤器

.and().addFilterBefore(new CustomGatewayFilter(), ConcurrentSessionFilter.class);