如何在获取访问令牌时使用OAuth2RestTemplate设置连接超时

时间:2019-01-08 05:15:43

标签: spring-oauth2

我们能够使用附加的代码快照获取访问令牌,但没有像使用spring restTemplate那样找到设置连接超时的任何方法。是否有任何方法可以使用OAuth2RestTemplate设置连接超时。

<bean id="bean" class="com.test.Provider">
            <constructor-arg name="context" ref="context" />
            <constructor-arg name="detail" ref="resourceDetails" />
        </bean>

        <bean id="context" class="org.springframework.security.oauth2.client.DefaultOAuth2ClientContext">
            <constructor-arg name="accessTokenRequest" ref="request" />
        </bean>

        <bean id="request" class="org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest"/>

        <bean id="resourceDetails" class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails"/>

3 个答案:

答案 0 :(得分:1)

聚会有点晚了,但如果您想知道如何使用 springboot 做到这一点,这是一种方法:

    @Bean
    protected OAuth2RestTemplate oauth2RestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(oAuthDetails());
        oAuth2RestTemplate.setRequestFactory(clientHttpRequestFactory);
        return oAuth2RestTemplate;
    }

    @Bean
    protected ClientHttpRequestFactory requestFactory() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setConnectTimeout(10000); //timeout in milliseconds
        requestFactory.setReadTimeout(10000); //timeout in milliseconds
        return requestFactory;
    }

其中oAuthDetails()是读取oauth配置属性的方法,类似这样:

    @Bean
    @ConfigurationProperties("path.to.your.oauth.properties.on.yml")
    protected ClientCredentialsResourceDetails oAuthDetails() {
        return new ClientCredentialsResourceDetails();
    }

答案 1 :(得分:0)

如果我是对的,那么将连接超时作为构造函数的参数赋予Spring RestTemplate的方法是通过将ClientHttpRequestFactory作为构造函数的参数赋予

RestTemplate(ClientHttpRequestFactory requestFactory)

例如,使用HttpComponentsClientHttpRequestFactory,可以如下设置与XML的RestClient的连接超时

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
  <constructor-arg name="requestFactory">
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
      <property name="connectTimeout" value="2000" />
      <property name="readTimeout" value="10000" />
    </bean>
  </constructor-arg>
</bean>

RestTemplate还提供了一种通过设置器设置requestFactory属性的方法,该设置器继承自InterceptingHttpAccessor,实际上构造函数本身似乎使用该设置器来设置作为构造函数参数给出的requestFactory。

因此,您可以通过设置器设置OAuth2RestTemplate的requestFactory。在XML中:

<bean id="oauth2RestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
  <constructor-arg name="resource" ref="resourceDetails" />
  <constructor-arg name="context" ref="context" />
  <property name="requestFactory">
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
      <property name="connectTimeout" value="2000" />
      <property name="readTimeout" value="10000" />
    </bean>
  </property>
</bean>

或者,在您的情况下,例如,可以为com.test.Provider类提供一个构造函数参数requestFactory,然后使用该参数在OAuth2RestTemplate中设置请求工厂,如下所示:

XML:

<bean id="bean" class="com.test.Provider">
  <constructor-arg name="context" ref="context" />
  <constructor-arg name="resourceDetails" ref="resourceDetails" />
  <constructor-arg name="requestFactory">
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
      <property name="connectTimeout" value="2000" />
      <property name="readTimeout" value="10000" />
    </bean>
  </constructor-arg>
</bean>

在您的代码集中

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(this.resourceDetails, this.context);
restTemplate.setRequestFactory(this.requestFactory);
String tokenString = restTemplate.getAccessToken().getValue();

在构造函数中设置this.requestFactory的值之后。

PS。我宁愿为整个类创建一个OAuth2RestTemplate作为私有字段,并在该类中重用它,除非您有理由为每个请求创建一个新的OAuth2RestTemplate。您可以在构造函数中创建它,就像您将上下文和详细信息作为构造函数参数提供一样,也可以在后构造/初始化方法中创建。甚至在没有在restTemplate之外使用context和resourceDetails的情况下,甚至可以将其作为构造函数参数或XML中的类的属性来提供。

编辑

进行更多研究后,看来问题可能比我想的要难。 OAuth2RestTemplate使用AccessTokenProvider获取访问令牌,默认情况下,它通过AccessTokenProviderChain实例使用AccessTokenProviders链,以支持不同类型的授予类型。似乎每个这些都使用自己的RestTemplate发送请求以获取访问令牌。不幸的是,似乎OAuth2RestTemplate没有提供一种简单的方法来设置默认AccessTokenProviders的restTemplates的requestFactory。

因此,如果我上面提出的解决方案不起作用(我怀疑这是可行的),我将使用以下我认为可行的方法。

Spring Security Oauth2中的所有默认AccessTokenProviders都扩展了OAuth2AccessTokenSupport类,该类也是创建内部RestTemplate的类。幸运的是,此类提供了一个setter来设置内部RestTemplate的requestFactory。因此,可以创建例如ClientCredentialsAccessTokenProvider的实例,并通过setRequestFactory(...)方法设置requestFactory。在XML中:

<bean id="clientCredentialsAccessTokenProvider class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider">
  <property name="requestFactory">
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
      <property name="connectTimeout" value="2000" />
      <property name="readTimeout" value="10000" />
    </bean>
  </property>
</bean>

由于某种原因,OAuth2RestTemplate无法提供一种访问默认AccessTokenProvider的方法,但是可以通过setAccessTokenProvider(AccessTokenProvider accessTokenProvider)设置器进行设置。要复制OAuth2RestTemplate的原始默认行为,必须提供一个AccessTokenProviderChain实例以及四个默认AccessTokenProvider,并设置其requestFactories。但是,您知道所访问的资源的类型为ClientCredentialsResourceDetails,因此只需在setAccessTokenProvider(...)设置器中设置单个ClientCredentialsAccessTokenProvider并设置ClientCredentialsAccessTokenProvider的requestFactory。

因此我们将获得以下代码:

XML:

<bean id="bean" class="com.test.Provider">
  <constructor-arg name="context" ref="context" />
  <constructor-arg name="resourceDetails" ref="resourceDetails" />
  <constructor-arg name="accessTokenProvider" ref="clientCredentialsAccessTokenProvider" />
</bean>

<bean id="clientCredentialsAccessTokenProvider" class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider">
  <property name="requestFactory">
    <bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
      <property name="connectTimeout" value="2000" />
      <property name="readTimeout" value="10000" />
    </bean>
  </property>
</bean>

然后在您的代码中,设置AccessTokenProvider:

OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(this.resourceDetails, this.context);
restTemplate.setAccessTokenProvider(this.accessTokenProvider);
String tokenString = restTemplate.getAccessToken().getValue();

在构造函数中设置this.accessTokenProvider的值之后。如果决定以XML创建OAuth2RestTemplate,则可以编写

<bean id="oauth2RestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
  <constructor-arg name="resource" ref="resourceDetails" />
  <constructor-arg name="context" ref="context" />
  <property name="accessTokenProvider" ref="clientCredentialsAccessTokenProvider" />
</bean>

其中的bean“ clientCredentialsAccessTokenProvider”的定义如上。

希望这行得通。

答案 2 :(得分:0)

上述解决方案的一个问题是ClientCredentialsAccessTokenProvider使用了增强的requestFactory:

private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory() {
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        super.prepareConnection(connection, httpMethod);
        connection.setInstanceFollowRedirects(false);
        connection.setUseCaches(false);
        ...
    }

    ...
};

因此,为了保留原始功能,您应该设置工厂的相同实现。