节俭应用编程接口网关——第2部分:春季统治


first part在这个系列中,我们研究了如何准备通过用户信息交换安全令牌的节俭包。Library是时候向前看了。

统治他们所有人的一个注解

注释驱动的开发是春天的方式。Spring可以通过许多注释来配置,这些注释从你的眼中隐藏了大量的逻辑。第一步包括创建注释,用beans和属性加载配置。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(ThriftGatewayConfiguration.class)
public @interface EnableThriftGateway {  
}

三层网关配置由一些满足我们需求的beans组成。它将在以后某个时候创建。

Zuul简介

Netflix Zuul是一种边缘服务,它路由和处理来自前端或移动设备的任何超文本传输协议请求,并将它们流式传输到后端。它有链接过滤器系统。每个过滤器都增加了新的功能。甚至写一封回信也是一种过滤。有三种过滤器类型:

  • 预过滤器
  • 途径
  • 后置过滤器

每种类型都有一个顺序。预过滤器首先执行。接下来,最后执行路由过滤器和后置过滤器。每个过滤器也有自己的顺序。

让我们创建它。

public class AuthenticationZuulFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 6;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequestWrapper request = (HttpServletRequestWrapper) ctx.getRequest();

        //actions are here

        return null;
    }
}

将它作为一个bean连接到Spring容器。

@Configuration
public class ThriftGatewayConfiguration {  
    @Bean
    public AuthenticationZuulFilter authenticationZuulFilter() {
        return new AuthenticationZuulFilter();
    }
}

魔法形态

好吧,我们来施点魔法。还记得我们在文章第一部分描述的配置吗?如下所示实现它:

@Configuration
public class ThriftGatewayConfiguration {  
    @Bean
    @ConditionalOnMissingBean(AuthTokenExchanger.class)
    AuthTokenExchanger authTokenExchanger() {
        throw new UnsupportedOperationException("You should implement AuthTokenExchanger bean");
    }

    @Bean
    @ConditionalOnMissingBean(TProtocolFactory.class)
    TProtocolFactory thriftProtocolFactory() {
        return new TBinaryProtocol.Factory();
    }

    @Bean
    public AuthenticationZuulFilter authenticationZuulFilter() {
        return new AuthenticationZuulFilter();
    }
}

注释ConditionalOnMissingBean如果在项目中定义了具有条件类的bean,则禁止创建默认bean。AuthTokenExchanger对于我们在上一篇文章中考虑的exchange外部令牌到内部令牌,需要。默认情况下,出于安全原因,我们不能实现任何逻辑并引发异常。因此,在项目中,开发人员必须实现他/她自己的逻辑,这是他们的责任。还不支持协议转换,因此只需要将一个协议注册为thriftProtocolFactory比恩。AuthenticationZuulFilter已经提前登记了。

过滤器内部

是时候深入研究了AuthenticationZuulFilter实现。首先,应该获得请求上下文:

RequestContext ctx = RequestContext.getCurrentContext();  
HttpServletRequestWrapper request = (HttpServletRequestWrapper) ctx.getRequest();  

下一步是创建MessageTranslator

MessageTransalator messageTransalator = new MessageTransalator(protocolFactory, authTokenExchanger);  

正面场景包含流程请求数据,将其写入requestEntity属性,并设置新的内容长度而不是原始长度:

byte[] processed = messageTransalator.process(request.getContentData());  
ctx.set("requestEntity", new ByteArrayInputStream(processed));  
ctx.setOriginContentLength(processed.length);  

如果提出了认证或其他特定于节俭的异常,我们需要用MessageTranslator并将其返回给客户端:

ctx.setSendZuulResponse(false);  
ctx.setResponseDataStream(new ByteArrayInputStream(new byte[]{}));

try {  
ctx.getResponse().getOutputStream().write(messageTransalator.processError(e));
} catch (Exception e1) {
log.error("unexpected error", e1);
    ctx.setResponseStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
}

有一些防止进一步服务调用处理所必需的上下文属性技巧。首先,ctx.setSendZuulResponse(false)阻止GZIPping响应。节俭的客户可能会因这种类型的包装而失败。其次,ctx.setResponseDataStream(new ByteArrayInputStream(new byte[]{}))需要通过Zuul响应滤波器中的肩部滤波器。

如果出现任何不节俭的例外,那么我们需要做同样的事情而不写回应,因为没有什么可以回报的。

示例

您可以在中找到示例thisGitHub上的存储库。在我们的示例中,实现了非常简单的逻辑:

@Bean
AuthTokenExchanger authTokenExchanger() {  
    return new AuthTokenExchanger<Token, TName>() {
        @Override
        public Token createEmptyAuthToken() {
            return new Token();
        }

        @Override
        public TName process(Token authToken) throws TException {
            if (authToken.getValue().equals("heisours")) {
                return new TName("John", "Smith");
            }

            throw new UnauthorizedException(ErrorCode.WRONG_LOGIN_OR_PASSWORD);
        }
    };
}

而且,我们可以用一种非常原始的Java方式来测试它(感谢节约):

@Test
public void testSimpleCall() throws Exception {  
    assertEquals("Hello John Smith", client.greet(new Token("heisours")));
}

@Test(expected = UnauthorizedException.class)
public void testUnauthorizedCall() throws Exception {  
    client.greet(new Token("heisnot"));
}

链接

您可以在GitHub上发现和分叉项目:https://github.com/aatarasoff/spring-thrift-api-gateway