アクティブユーザーのユーザー詳細を取得する方法 質問する

アクティブユーザーのユーザー詳細を取得する方法 質問する

私のコントローラーでは、アクティブな(ログインしている)ユーザーが必要な場合、実装を取得するために次の操作を実行していますUserDetails

User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());

問題なく動作しますが、このような場合には Spring の方が楽だと思います。UserDetailsコントローラーまたはメソッドのいずれかに自動配線する方法はありますか?

たとえば、次のようになります。

public ModelAndView someRequestHandler(Principal principal) { ... }

しかし、 ではなくUsernamePasswordAuthenticationTokenが手に入るのですかUserDetails?

エレガントな解決策を探しています。何かアイデアはありますか?

ベストアンサー1

前文:@AuthenticationPrincipalSpring-Security 3.2 以降では、この回答の最後に便利な注釈が説明されています。これは、Spring-Security >= 3.2 を使用する場合に最適な方法です。

次の場合:

  • Spring-Securityの古いバージョンを使用する
  • プリンシパルまたはデータベースに保存されている情報(ログインやIDなど)を使用して、カスタムユーザーオブジェクトをデータベースからロードする必要があります。
  • HandlerMethodArgumentResolverまたは がこれをエレガントな方法で解決する方法を学びたい、またはとWebArgumentResolverの背景を知りたいだけです( は に基づいているため)。@AuthenticationPrincipalAuthenticationPrincipalArgumentResolverHandlerMethodArgumentResolver

読み続けてください。そうでない場合は、@AuthenticationPrincipalRob Winch(の著者@AuthenticationPrincipal)とルーカス・シュメルツァイゼン(彼の答えに対して)。

(ちなみに私の回答は少し古いもの(2012年1月)なので、ルーカス・シュメルツァイゼンSpring Security 3.2 に基づくアノテーション ソリューションで最初に登場したもの@AuthenticationPrincipal


コントローラーで使用できます

public ModelAndView someRequestHandler(Principal principal) {
   User activeUser = (User) ((Authentication) principal).getPrincipal();
   ...
}

一度だけ必要な場合は問題ありません。しかし、複数回必要な場合は、通常はフレームワークによって隠されるはずのインフラストラクチャの詳細がコントローラーに混入するため、見苦しいものになります。

したがって、実際に必要なのは次のようなコントローラーです。

public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
   ...
}

したがって、実装する必要があるのはWebArgumentResolver方法があります

Object resolveArgument(MethodParameter methodParameter,
                   NativeWebRequest webRequest)
                   throws Exception

これは Web リクエスト (2 番目のパラメータ) を取得し、Userメソッド引数 (最初のパラメータ) を担当する場合はそれを返す必要があります。

Spring 3.1以降では、HandlerMethodArgumentResolverSpring 3.1+ を使用している場合は、それを使用する必要があります。(この回答の次のセクションで説明します))

public class CurrentUserWebArgumentResolver implements WebArgumentResolver{

   Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
        if(methodParameter is for type User && methodParameter is annotated with @ActiveUser) {
           Principal principal = webRequest.getUserPrincipal();
           return (User) ((Authentication) principal).getPrincipal();
        } else {
           return WebArgumentResolver.UNRESOLVED;
        }
   }
}

カスタム アノテーションを定義する必要があります。User のすべてのインスタンスを常にセキュリティ コンテキストから取得する必要があるが、コマンド オブジェクトではない場合、これをスキップできます。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}

設定では、これを追加するだけです:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
    id="applicationConversionService">
    <property name="customArgumentResolver">
        <bean class="CurrentUserWebArgumentResolver"/>
    </property>
</bean>

@見る:Spring MVC @Controller メソッドの引数をカスタマイズする方法を学ぶ

Spring 3.1 を使用している場合は、WebArgumentResolver よりも HandlerMethodArgumentResolver が推奨されることに注意してください。 - Jay のコメントを参照してください。


HandlerMethodArgumentResolverSpring 3.1以降も同様

public class CurrentUserHandlerMethodArgumentResolver
                               implements HandlerMethodArgumentResolver {

     @Override
     public boolean supportsParameter(MethodParameter methodParameter) {
          return
              methodParameter.getParameterAnnotation(ActiveUser.class) != null
              && methodParameter.getParameterType().equals(User.class);
     }

     @Override
     public Object resolveArgument(MethodParameter methodParameter,
                         ModelAndViewContainer mavContainer,
                         NativeWebRequest webRequest,
                         WebDataBinderFactory binderFactory) throws Exception {

          if (this.supportsParameter(methodParameter)) {
              Principal principal = webRequest.getUserPrincipal();
              return (User) ((Authentication) principal).getPrincipal();
          } else {
              return WebArgumentResolver.UNRESOLVED;
          }
     }
}

設定ではこれを追加する必要があります

<mvc:annotation-driven>
      <mvc:argument-resolvers>
           <bean class="CurrentUserHandlerMethodArgumentResolver"/>         
      </mvc:argument-resolvers>
 </mvc:annotation-driven>

@見るSpring MVC 3.1 HandlerMethodArgumentResolver インターフェースを活用する


Spring-Security 3.2 ソリューション

Spring Security 3.2 (Spring 3.2 と混同しないでください) には独自の組み込みソリューションがあります。@AuthenticationPrincipalorg.springframework.security.web.bind.annotation.AuthenticationPrincipal)これは、ルーカス・シュメルツァイゼンの答え

ただ書いているだけです

ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
    ...
 }

これを機能させるには、AuthenticationPrincipalArgumentResolver( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver) を登録する必要があります。これは、上記の Spring 3.1 ソリューションで説明したのと同じ方法で、「アクティブ化」するか@EnableWebMvcSecurity、この Bean を内部に登録することによって行いmvc:argument-resolversます。

@見るSpring Security 3.2 リファレンス、第 11.2 章。@AuthenticationPrincipal


Spring-Security 4.0 ソリューション

これは Spring 3.2 ソリューションと同様に機能しますが、Spring 4.0 では@AuthenticationPrincipalAuthenticationPrincipalArgumentResolver別のパッケージに「移動」されました。

(ただし、古いパッケージ内の古いクラスはまだ存在するため、混在させないでください!)

ただ書いているだけです

import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
    ...
}

これを機能させるには、( org.springframework.security.web.method.annotation.)を登録する必要がありますAuthenticationPrincipalArgumentResolver。これは、上記の Spring 3.1 ソリューションで説明したのと同じ方法で、「アクティブ化」する@EnableWebMvcSecurityか、この Bean を内部に登録することによって行いmvc:argument-resolversます。

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
    </mvc:argument-resolvers>
</mvc:annotation-driven>

@見るSpring Security 5.0 リファレンス、第 39.3 章 @AuthenticationPrincipal

おすすめ記事