2つの個別のSpring Bootアプリケーションがあり、1つはOAuth 2認証サーバーとして機能し、もう1つはリソースサーバーとして機能します。リソースサーバーでSpringのRemoteTokenServices
を使用して、承認サーバーからのトークンをチェックしています。現在、リソースサーバーアプリケーションで保護されたコントローラーコードを定義しようとしていますが、UserDetails
クラスをOAuth 2メカニズムを通じて提供される認証プリンシパルにマップする方法がわかりません。
カスタムTokenEnhancer
を使用して認証サーバーを設定しました。これにより、/oauth/check_token?token=<token>
がカスタムフィールドを返し、リソースサーバーコントローラーにマップするように、トークンに詳細が追加されます。
承認サーバーがリソースサーバーでもあるよりモノリシックなセットアップでは、認証されたプリンシパルを次のように利用するコントローラーメソッドを定義できます。
//User implements UserDetails
public Map<String, Object> getResource(@AuthenticationPrincipal User user) {
//code that uses the user object
}
ただし、これはより分散されたアプローチでは簡単には機能しないようです。マッピングは失敗し、user
パラメータは最終的にnullオブジェクトになります。私は次のアプローチを試してみました:
public Map<String, Object> getResource(Authentication authentication) {
//code that uses the authentication object
}
上記のコードは認証の詳細を正常にマップしますが、前述のTokenEnhancer
を使用して設定したカスタムフィールドに直接アクセスする方法はありません。これに関するSpringドキュメントから何も見つけられないようです。
この問題を解決するために、まずアーキテクチャの背景について少し説明します。 _@AuthenticationPrincipal
_によって自動的にマップされるUserDetails
オブジェクトは、アクティブなprincipal
オブジェクトのAuthentication
フィールドから取得されます。リソースサーバーコントローラーは、メソッドパラメーターの一部として宣言するだけで、Spring OAuth2セキュリティフレームワークのAuthentication
の特殊なインスタンスである_OAuth2Authencation
_オブジェクトにアクセスできます。
_public void controllerMethod(OAuth2Authentication authentication) {
//controller definition
}
_
これを知って、問題はAuthentication
オブジェクトのgetPrincipal()
メソッドがカスタムUserDetails
クラスのインスタンスであることを確認する方法に移ります。リソースサーバーアプリケーションで使用するRemoteTokenServices
は、AccessTokenConverter
のインスタンスを使用して、承認サーバーから送信されたトークンの詳細を解釈します。デフォルトでは、DefaultAccessTokenConverter
を使用します。これは、認証プリンシパルをユーザー名として設定するだけで、これはString
です。このコンバーターは、UserAuthenticationConverter
を使用して、許可サーバーからのデータをAuthentication
のインスタンスに変換します。これは私がカスタマイズする必要があったものです:
_DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {
@Override
public Authentication extractAuthentication(Map<String, ?> map) {
Authentication authentication = super.extractAuthentication(map);
// User is my custom UserDetails class
User user = new User();
user.setSpecialKey(map.get("specialKey").toString());
return new UsernamePasswordAuthenticationToken(user,
authentication.getCredentials(), authentication.getAuthorities());
}
});
tokenServices.setAccessTokenConverter(tokenConverter);
_
これらすべての設定が完了すると、_@AuthenticationPrincipal
_メカニズムが期待どおりに機能するようになります。
次のxmlのように、AuthenticationPrincipalArgumentResolver
を有効にしましたか?
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
また、UserDetails
を実装して独自のCustomerUser object
を返す必要がある場合は、アノテーションを使用してプリンシパルを直接取得できます。