Spring XD OAuth Sink 单元测试无法获取资源的新访问令牌 'null'

Spring XD OAuth Sink unit test Unable to obtain a new access token for resource 'null'

我正在尝试为我为 Spring XD 创建的接收器编写集成测试。这是我的 ModuleConfiguration.java

@Configuration
@EnableIntegration
public class ModuleConfiguration {

    private OAuth2AccessToken token;

    @Bean
    public MessageChannel input() {
        return new DirectChannel();
    }

    @Bean
    protected OAuth2ProtectedResourceDetails resource() {
        BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
        resource.setAccessTokenUri("https://xxxxxxxxxxx");
        resource.setClientId("id");
        resource.setClientSecret("secret");
        resource.setGrantType("authorization_code");
        return resource;
    }

    @Bean
    public OAuth2RestTemplate oAuthTemplate() {
        AccessTokenRequest atr = new DefaultAccessTokenRequest();
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
        return restTemplate;
    }

    @Bean
    public HeaderMapper<HttpHeaders> headerMapper() {
        HeaderMapper<HttpHeaders> mapper = new DefaultHttpHeaderMapper();
        HttpHeaders headers = new HttpHeaders();
        token = oAuthTemplate().getAccessToken();
        String authHeader = "Bearer " + token.getValue();

        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("Authorization", authHeader);
        mapper.toHeaders(headers);

        return mapper;
    }

    @ServiceActivator(inputChannel="inputChannel")
    @Bean
    public MessageHandler httpout() {
        HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("https://yyyyyyyyy");
        handler.setCharset("UTF-8");
        handler.setHttpMethod(HttpMethod.POST);
        handler.setHeaderMapper(headerMapper());
        return handler;
    }
}

我实现测试的方式与编写处理器测试的方式相同,并告诉 spring xd 这个模块是处理器,因为这是它所期望的。不确定,但我认为这不重要,我遇到的异常与 OAuth 有关。这里是SinkTest.java

public class SinkTest {

    private static SingleNodeApplication application;

    private static int RECEIVE_TIMEOUT = 5000;

    private static String moduleName = "oauth-sink";

    @BeforeClass
    public static void setUp() {
        application = new SingleNodeApplication().run();
        SingleNodeIntegrationTestSupport singleNodeIntegrationTestSupport = new SingleNodeIntegrationTestSupport(
                application);
        singleNodeIntegrationTestSupport
                .addModuleRegistry(new SingletonModuleRegistry(ModuleType.processor, moduleName));
    }

    @Test
    public void test() {
        String streamName = "sinkTest";
        byte[] encoded = null;
        String data = null;
        try {
            encoded = Files.readAllBytes(Paths.get("src/test/resources/dataunit.json"));
            data = new String(encoded, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
            fail("Exception thrown");
        }

        String processingChainUnderTest = moduleName;
        SingleNodeProcessingChain chain = chain(application, streamName, processingChainUnderTest);
        chain.sendPayload(data);
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> result = (List<Map<String, Object>>) chain.receivePayload(RECEIVE_TIMEOUT);

        // Unbind the source and sink channels from the message bus
        chain.destroy();
        // an exception is thrown by zookeeper when the spring xd container shuts down after the test passes
    }
}

我的 ModuleConfiguration 的这一行出现异常 token = oAuthTemplate().getAccessToken();

Caused by: error="access_denied", error_description="Unable to obtain a new access token for resource 'null'. The provider manager is not configured to support it."
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:146)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:118)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)

如果我像这样在 ModuleConfiguration 中使用 client_credentials 作为 GrantType

@Bean
    protected OAuth2ProtectedResourceDetails resource() {
        BaseOAuth2ProtectedResourceDetails resource = new ClientCredentialsResourceDetails();
        resource.setAccessTokenUri("https://xxxxxxx");
        resource.setClientId("id");
        resource.setClientSecret("secret");
        resource.setGrantType("client_credentials");
        return resource;
    }

我明白了

Caused by: org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:107)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    ... 29 more

当我只有 clientId 和 secret 时,正确的授权类型是什么?我的 ModuleConfiguration 中是否缺少某些内容?

更新 我将 @ServiceActivator 中的 inputChannel 更改为正确的值,现在我得到了与之前 BaseOAuth2ProtectedResourceDetails 相同的异常。现在使用 ClientCredentialsResourceDetails

得到一个不同的异常
Caused by: java.lang.IllegalArgumentException: Map has no value for 'object-type'
    at org.springframework.web.util.UriComponents$MapTemplateVariables.getValue(UriComponents.java:276)
    at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:221)
    at org.springframework.web.util.HierarchicalUriComponents$FullPathComponent.expand(HierarchicalUriComponents.java:650)
    at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:319)
    at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:46)
    at org.springframework.web.util.UriComponents.expand(UriComponents.java:152)
    at org.springframework.web.util.UriComponentsBuilder.buildAndExpand(UriComponentsBuilder.java:376)
    at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:376)
    ... 35 more

首先尝试将 OAuthRestTemplate 注入 HttpExecutionMessageHandler.

并且根本不要使用那个 headerMapper,即使像豆子一样。在我看来,这正是我们拥有 OAuth RestTemplate 扩展的原因。

您的另一个问题是接收器及其 service-activator 的错误通道。对,那一定是 input bean,但使用与 @ServiceActivator 相同的名称。这是你 Dispatcher has no subscribers.

的根源
@ServiceActivator(inputChannel="inputChannel")
@Bean
public MessageHandler httpout() {
    HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("https://yyyyyyyyy", oAuthTemplate());
    handler.setCharset("UTF-8");
    handler.setHttpMethod(HttpMethod.POST);
    return handler;
}

如果您在 URL 中有一些变量,例如 https://foo.bar/{foo}/{bar},您必须提供 setUriVariableExpressions(Map<String, Expression> uriVariableExpressions) 以在运行时针对 requestMessage 解析它们:http://docs.spring.io/spring-integration/reference/html/http.html#_mapping_uri_variables