私のコントローラーでは、アクティブな(ログインしている)ユーザーが必要な場合、実装を取得するために次の操作を実行していますUserDetails
。
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());
問題なく動作しますが、このような場合には Spring の方が楽だと思います。UserDetails
コントローラーまたはメソッドのいずれかに自動配線する方法はありますか?
たとえば、次のようになります。
public ModelAndView someRequestHandler(Principal principal) { ... }
しかし、 ではなくUsernamePasswordAuthenticationToken
が手に入るのですかUserDetails
?
エレガントな解決策を探しています。何かアイデアはありますか?
ベストアンサー1
前文:@AuthenticationPrincipal
Spring-Security 3.2 以降では、この回答の最後に便利な注釈が説明されています。これは、Spring-Security >= 3.2 を使用する場合に最適な方法です。
次の場合:
- Spring-Securityの古いバージョンを使用する
- プリンシパルまたはデータベースに保存されている情報(ログインやIDなど)を使用して、カスタムユーザーオブジェクトをデータベースからロードする必要があります。
HandlerMethodArgumentResolver
または がこれをエレガントな方法で解決する方法を学びたい、またはとWebArgumentResolver
の背景を知りたいだけです( は に基づいているため)。@AuthenticationPrincipal
AuthenticationPrincipalArgumentResolver
HandlerMethodArgumentResolver
読み続けてください。そうでない場合は、@AuthenticationPrincipal
Rob 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以降では、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 {}
設定では、これを追加するだけです:
<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
)これは、ルーカス・シュメルツァイゼンの答え
ただ書いているだけです
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 では@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
。これは、上記の 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