1. ホーム
  2. java

[解決済み] アクティブユーザーのUserDetailsを取得する方法

2022-04-22 05:14:24

質問

コントローラで、アクティブな(ログインしている)ユーザーを必要とする場合、次のようにします。 UserDetails を実装しています。

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

これは問題なく動作しますが、このような場合、Springを使えばもっと簡単に生活できると思います。このような場合に UserDetails をコントローラまたはメソッドのどちらかに自動的に組み込むことができますか?

例えば、こんな感じ。

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

しかし、その代わりに UsernamePasswordAuthenticationToken が表示されます。 UserDetails の代わりに?

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

どのように解決するのですか?

前文です。 Spring-Security 3.2以降では、以下のような素敵なアノテーションが用意されています。 @AuthenticationPrincipal この回答の最後に記載されています。Spring-Security >= 3.2を使用する場合は、この方法がベストです。

するとき。

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

であれば、そのまま読み進めてください。 @AuthenticationPrincipal の作者であるRob Winchに感謝します。 @AuthenticationPrincipal ) と ルーカス・シュメルツァイゼン (の回答に対して)。

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


そして、コントローラで使用することができます。

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

これは、ウェブリクエスト(2番目のパラメータ)を取得し、そのリクエストに応じた User メソッドの引数(最初のパラメータ)に責任を感じている場合。

Spring 3.1以降では、新しい概念として HandlerMethodArgumentResolver . もしSpring 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 {}

コンフィギュレーションでは、これだけ追加すればOKです。

<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のコメント参照


と同じです。 HandlerMethodArgumentResolver Spring 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 と混同しないでください) には、独自のビルドインソリューションがあります。 @AuthenticationPrincipal ( org.springframework.security.web.bind.annotation.AuthenticationPrincipal ) . これをうまく表現したのが Lukas Schmelzeisenの回答

と書くだけです。

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

これを動作させるためには AuthenticationPrincipalArgumentResolver ( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver ) : 活性化することである。 @EnableWebMvcSecurity の中でこのビーンを登録するか mvc:argument-resolvers - 上記のSpring 3.1ソリューションで説明したのと同じ方法です。

参照 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 : "activating"のどちらかで。 @EnableWebMvcSecurity の中でこのビーンを登録するか mvc:argument-resolvers - 上記のSpring 3.1ソリューションで説明したのと同じ方法です。

<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