[解決済み] アクティブユーザーのUserDetailsを取得する方法
質問
コントローラで、アクティブな(ログインしている)ユーザーを必要とする場合、次のようにします。
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
がエレガントな方法でこれを解決できるのか、あるいは、その背景を知りたいのか。@AuthenticationPrincipal
とAuthenticationPrincipalArgumentResolver
(をベースにしているため)。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では
@AuthenticationPrincipal
と
AuthenticationPrincipalArgumentResolver
は別のパッケージに移動しました。
-
org.springframework.security.core.annotation.AuthenticationPrincipal
-
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
(ただし、旧パッケージの旧クラスはまだ存在するので、混在させないでください!)
を書いているだけです。
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
関連
-
Javaクラスローダーにソースコードから潜り込む
-
SocketTimeoutExceptionの解決方法です。読み込みがタイムアウトした
-
起動時にEclipseエラーが発生しました。起動中に内部エラーが発生しました。java.lang.NullPoin: "Javaツーリングの初期化 "中に内部エラーが発生しました。
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] Java Mapの各エントリを効率的に反復処理するには?
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] cURLでJSONデータをPOSTするにはどうすればよいですか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] Javaで文字列値からenum値を取得する方法
-
[解決済み】Javaではfinallyブロックは必ず実行されるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
java.util.NoSuchElementException 原因解析と解決方法
-
Java Exceptionが発生しました エラー解決
-
this()の呼び出しはコンストラクタ本体の最初の文でなければならない 例外解決と原因分析
-
プロローグでのコンテンツは禁止されています
-
JDKの設定時にjava.dllが見つからない、java SE Runtime Environmentが見つからない問題が発生しました。
-
Spring BootのテストメソッドFailed to load ApplicationContextの問題を解決する
-
リソースの読み込みに失敗しました。サーバーはステータス500(内部サーバーエラー)で応答しました。
-
javaでよく使われる英単語
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
[解決済み] Spring Securityを使用する場合、Beanで現在のユーザー名(つまりSecurityContext)情報を取得する適切な方法は何ですか?