2

私はSpringブートアプリケーションでOAuth2RestTemplateを使用しています。すべての認証情報をカプセル化するため、いくつかのリソースを使用して作業しますので、トークンやその他の認証について心配する必要はありませんもの。複数スレッドのコンテキストでOAuth2RestTemplateを使用する

リクエストが並行して送信されるまで、すべて正常に動作します。そのためOAuth2RestTemplateの

は、私は、マルチスレッド環境でそれを使用しようとしているとき、私は次の例外を取得し、(それがユーザーのセッション関連の情報が含まれているとして、地元である)Sessionスコープを持って

org.springframework.beans.factory.BeanCreationException: 'scopedTarget.oauth2ClientContext'という名前のBeanを作成中にエラーが発生しました:スコープ 'session'は現在のスレッドではアクティブではありません。 シングルトンから参照する場合は、このBeanのスコープ付きプロキシを定義することを検討してください。 ネストされた例外はjava.lang.IllegalStateExceptionです:スレッドバインドされた要求が見つかりません: 実際のWeb要求の外に、 の要求属性を参照していますか、元の受信スレッド外の要求を処理していますか?実際にWebリクエスト内で操作していて、まだ というメッセージが表示されている場合は コードがDispatcherServlet/DispatcherPortletの外で実行されている可能性があります。この場合、 RequestContextListenerまたはRequestContextFilterを使用して現在の リクエストを公開します。

私は理解したようにコードが実行されているこれらの別々のスレッドは、セッションに配線されていないので、これは起こります。

私が今見つけた唯一の解決策は、セッションで新しいスレッドを手動でコードにバインドすることですが、それは好きではありません。

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); 

    Stream.of(1, 2, 3).parallel().forEach(it -> { 
     RequestContextHolder.setRequestAttributes(requestAttributes); 
     //do something 
     RequestContextHolder.resetRequestAttributes(); 
    }); 

    RequestContextHolder.setRequestAttributes(requestAttributes); 

は、同様の問題が議論されたticket on Spring Jiraありますが、それでも私はまだOAuth2RestTemplateに関連するいくつかの解決策があることを願っています。

誰かがこれに会い、それをどのように解決したのかと思います。

答えて

0

セッションまたはリクエストスコープを使用するには、RequestContextListenerを@ConfigurationクラスのBeanとして公開する必要があります。例えば、this threadを参照してください。

0

独自のBeanを作成した後で、複数のスレッドで簡単にOAuth2RestTemplateを使用でき、正しく自動配線されていることを確認しました。私は正確に同じエラーメッセージが出たし、それは私が前に作成されていたOAuth2RestTemplate取得していないことが判明する前に

:特に

@Bean 
@Autowired 
public OAuth2RestTemplate oAuth2RestTemplate(
    OAuth2ProtectedResourceDetails resourceDetails, 
    SpringClientFactory clientFactory) { 

    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails); 
    restTemplate.setRequestFactory(new RibbonClientHttpRequestFactory(clientFactory)); 

    return restTemplate; 
} 

は、要求工場はRestTemplateには存在しませんでした実際にはそれはnullでした。さらに、私は実際には複数の異なるOAuth2RestTemplate beanを持っていましたが、@Autowiredはすべて同じインスタンスを返しました。

キーがOAuth2RestOperationsConfigurationであることが判明:

@Bean 
@Primary 
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext, 
     OAuth2ProtectedResourceDetails details) { 
    OAuth2RestTemplate template = new OAuth2RestTemplate(details, 
      oauth2ClientContext); 
    return template; 
} 

ため@Primary注釈のため、すべての@Autowiredのインスタンスは明らかに、このいずれかを取得します。この場合は、パラメータ名で取得したいBeanを指定していましたが、これまでは通常動作していました。 @Qualifier注釈の追加

は、この問題を解決:

@Autowired 
@Qualifier("myOwnOAuth2RestTemplate") 
OAuth2RestTemplate oAuth2RestTemplate; 

今、正しいインスタンスが返され、要求を行う際に、アプリケーション構成で構成されているように、認証サーバは、のOAuth2トークンを取得するために呼び出されますsecurity.oauth2.client

しかし、新しいスレッドの中からRestTemplateをautowireしようとはしませんでした。代わりに、私は議論としてそれを渡します。私はこれが違いを生むかどうかは完全には分かっていませんが、getAccessToken()が要求実行中にRestTemplateによって呼び出されているので、新しいスレッドにautowiredしたときにも動作するはずです。

+0

あなたはBeanシングルトンを作ったので、Springは別のスレッドにシングルトンを結びつけることができるので、うまくいくでしょう。しかし、ここで問題となるのは、oAuth2RestTemplateには、ユーザーの関連する認証情報を格納するためのセッションスコープがデフォルトで設定されているため、各ユーザーは独自のBeanを使用できます。私は、これがSingleton oAuth2RestTemplateで正しく動作するかどうかはわかりません。 – ikryvorotenko

+0

@ikryvorotenko 'SecurityContext'で認証されたプリンシパルのOAuth2アクセストークンを使いたい場合、実際にはすべてのユーザに別々のBeanは必要ありません。 'OAuth2ClientContext'を' SecurityContext'の 'Authentication'からのトークンで更新することができます。 セッションスコープのBeanは、最後にSpringのプロキシマジックのために「本当の」シングルトンではないと思います。 実際には、私の答えに記載されているアプローチに基づいていろいろな 'OAuth2RestTemplate' Beanと、トークンを取得するために静的なユーザー名/パスワードの資格情報を使用する追加のBeanをうまく使用しています。 –

関連する問題