gpt4 book ai didi

java - 无法将 Spring-Integration 与 RestTemplate 连接起来

转载 作者:行者123 更新时间:2023-11-30 02:44:44 24 4
gpt4 key购买 nike

我对 Spring 集成框架完全是菜鸟。

我正在尝试使用使用 OAuth2 的 REST API。我正在使用 Spring Integration 基于 xml 的配置。

我的问题是,似乎无法正确连接网关和休息模板来发送 token 请求的正文(多部分)

这是在我的 spring 集成配置文件中:

spring-integration-context.xml

<!-- Rest Template -->
<bean id="oAuth2RestTemplate"
class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg ref="clientCredentialsResource"/>
</bean>

<!-- Used by Rest Template -->
<bean id= "clientCredentialsResource"
class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails">
<property name="clientId" value="${oauth2.clientId}" />
<property name="clientSecret" value="${oauth2.clientSecret}" />
<property name="accessTokenUri" value="${oauth2.accessTokenUri}" />
</bean>

<!-- Channels for requesting token -->
<int:channel id="tokenRequestChannel"/>
<int:channel id="tokenResponseChannel"/>

<!-- Gateway for requesting token -->
<int-http:outbound-gateway id="authRequestGateway"
request-channel="tokenRequestChannel"
url="${oauth2.endPointUri}"
reply-timeout="30000"
http-method="GET"
rest-template="oAuth2RestTemplate"
reply-channel="tokenResponseChannel"
charset="UTF-8"
expected-response-type="java.lang.String">
</int-http:outbound-gateway>

要获取初始 token ,我知道我需要在 header 中发布我的凭据,如下所示:

Method: POST
Authorization: Basic <base64-encoded clientId:clientSecret>
Content-Type: application/x-www-form-urlencoded

并向正文添加多部分(表单)

grant_type=client_credentials&scope=read

API 要求字符串 grant_type=client_credentials&scope=read 位于请求正文(而不是 URL)中,因为这是一个 POST(而不是 GET )。

我尝试了一些事情(太多了,无法记住/重述所有内容),但是我不确定在哪里/如何将有效负载放入我的请求中。

我遗漏了一些东西(明显的?),而且我现在不知道它是什么。

这是我在日志中得到的内容(请求/响应):

2016-11-10 16:46:22.429 DEBUG 6384 --- [ask-scheduler-3] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader@2d1f9cc810 pairs: {POST [redacted]/oauth/token HTTP/1.1: null}{Authorization: Basic [redacted]}{Accept: application/json, application/x-www-form-urlencoded}{Content-Type: application/x-www-form-urlencoded}{Cache-Control: no-cache}{Pragma: no-cache}{User-Agent: Java/1.8.0_72}{Host: [redacted]}{Connection: keep-alive}{Content-Length: 29} 2016-11-10 16:46:22.584 DEBUG 6384 --- [ask-scheduler-3] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader@29200db310 pairs: {null: HTTP/1.1 400 Bad Request}{Cache-Control: no-cache}{Pragma: no-cache}{Content-Type: application/json; charset=utf-8}{Expires: -1}{Server: [redacted]}{[redacted]}{[redacted]}{Date: Fri, 11 Nov 2016 00:46:48 GMT}{Content-Length: 46} 2016-11-10 16:46:22.586 ERROR 6384 --- [ask-scheduler-3] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [redacted]; nested exception is error="access_denied", error_description="Access token denied." at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:409) at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109) at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127) at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148) at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:121) at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77) at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:423) at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:373) at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115) at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45) at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:105) at org.springframework.integration.endpoint.SourcePollingChannelAdapter.handleMessage(SourcePollingChannelAdapter.java:195) at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:272) at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58) at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190) at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186) at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353) at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55) at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51) at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: error="access_denied", error_description="Access token denied." at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:142) at org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider.obtainAccessToken(ClientCredentialsAccessTokenProvider.java:44) at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:142) 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) at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:615) at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:595) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:516) at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:382) ... 30 more Caused by: error="invalid_request", error_description="OAuth Error", message="{ "error": "invalid_scope" }" at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:120) at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3789) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2913) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:225) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:205) at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193) at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:235) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:667) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:588) at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137) ... 41 more

因此,据我所知,我收到了“拒绝访问”消息,因为我无法在请求正文中设置范围。

注释1

此外,我已经查看了示例项目中的代码,但没有看到我的问题的答案。

注释2

我已经(通过 POSTMAN)验证了凭据、端点(URI)、范围等是否正确。

更新1

根据 @Artem-Bilan 的评论,我将方法更改为 POST 并添加了以下代码以将正文包含在请求中。

<!-- Add Payload -->
<int:inbound-channel-adapter id="oauth2ChannelAdapter" channel="tokenRequestChannel"
ref="grantAndScope" method="getGrantTypeAndScope">
<!-- Triggering requests every 5 seconds -->
<int:poller fixed-delay="5000" />
</int:inbound-channel-adapter>

<!-- Bean with Grant & Scope Payload -->
<bean id="grantAndScope" class="com.AuthTypeAndScopeInfo"/>

AuthTypeAndScopeInfo.java

public class AuthTypeAndScopeInfo {

/* adds grant type and scope as body to message */
public MultiValueMap<String, String> getGrantTypeAndScope() {
// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();

body.add("grant_type", "client_credentials");
body.add("scope", "read");

return body;
}
}

但是,结果是相同的:/

最佳答案

最终,我没有使用Oauth2RestTemplate

相反,我使用了下面的代码。该代码基本上首先创建一个 Map 有效负载(正如 Artem 在他的回答中所建议的那样),并注入(inject)第一个请求的 header 。

然后,它使用第一个请求的响应(包含访问 token )将获得的 token 注入(inject)所有后续请求的 header 中。

这里可能还有一些优化的空间,但目前来说,这足以满足我的需求。

AuthTypeAndScopeInfo.java

public class AuthTypeAndScopeInfo {

/* adds grant type and scope as body to message */
public MultiValueMap<String, String> getGrantTypeAndScope() {
// Create the request body as a MultiValueMap
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();

body.add("grant_type", "client_credentials");
body.add("scope", "read");

return body;
}
}

spring-integration-context.xml

<!-- Add Payload -->
<int:inbound-channel-adapter id="oauth2ChannelAdapter" channel="preTokenRequestChannel"
ref="grantAndScope" method="getGrantTypeAndScope">
<!-- Triggering requests every 5 seconds -->
<int:poller fixed-delay="5000" />
</int:inbound-channel-adapter>

<!-- POJO with Grant & Scope Payload -->
<bean id="grantAndScope" class="com.AuthTypeAndScopeInfo"/>

<!-- Adding headers for Token Request -->
<int:header-enricher input-channel="preTokenRequestChannel"
output-channel="tokenRequestChannel">
<int:header name="Authorization" value="Basic <clientId:clientSecret>"/>
<int:header name="Content-Type" value="application/x-www-form-urlencoded"/>
</int:header-enricher>

<!-- Channels for requesting token -->
<int:channel id="tokenRequestChannel"/>
<int:channel id="tokenResponseChannel"/>

<!-- Channels for Authenticated requests (with valid token) -->
<int:channel id="authenticatedRequestChannel"/>
<int:channel id="authenticatedResponseChannel"/>

<!-- Gateway for requesting token -->
<!-- REST request to authorization server for a token -->
<!-- replies time out after 30 seconds -->
<int-http:outbound-gateway id="tokenRequestGateway"
request-channel="tokenRequestChannel"
url="${security.oauth2.client.accessTokenUri}"
reply-timeout="30000"
http-method="POST"
reply-channel="tokenResponseChannel"
charset="UTF-8"
expected-response-type="java.lang.String">
</int-http:outbound-gateway>

<!-- Adding headers for Authenticated Request (contains newly obtained token) -->
<int:chain input-channel="tokenResponseChannel"
output-channel="authenticatedRequestChannel">
<int:header-enricher>
<!-- Adds token_type and the actual (authenticated)
access_token to the header of the next request
(overwriting the Basic <...> previous entry) -->
<int:header name="Authorization" overwrite="true"
expression="#jsonPath(payload,'$.token_type') + ' ' + #jsonPath(payload,'$.access_token')" />
</int:header-enricher>
</int:chain>

<!-- REST request with pre-authorized token -->
<!-- replies time out after 30 seconds -->
<int-http:outbound-gateway id="authenticatedRequestGateway"
request-channel="authenticatedRequestChannel"
url="${security.oauth2.client.endPointUri}"
reply-timeout="30000"
http-method="GET"
reply-channel="authenticatedResponseChannel"
charset="UTF-8"
expected-response-type="java.lang.String">
</int-http:outbound-gateway>

关于java - 无法将 Spring-Integration 与 RestTemplate 连接起来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40539689/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com