前言:自从Spring-Security 3.2版本以后,有一个很好的注解@AuthenticationPrincipal
,在本答案的末尾有描述。当您使用Spring-Security >= 3.2时,这是最好的选择。
当您:
- 使用旧版本的Spring-Security,
- 需要通过在主体中存储的某些信息(如登录或ID)从数据库加载自定义用户对象,或者
- 想要了解
HandlerMethodArgumentResolver
或WebArgumentResolver
如何以优雅的方式解决此问题,或者只是想要了解@AuthenticationPrincipal
和AuthenticationPrincipalArgumentResolver
背后的背景(因为它基于HandlerMethodArgumentResolver
)
那么请继续阅读——否则只需使用@AuthenticationPrincipal
,并感谢Rob Winch(@AuthenticationPrincipal
的作者)和Lukas Schmelzeisen(因他的回答)。
顺便提一句:我的回答有点旧了(2012年1月),所以基于Spring Security 3.2的@AuthenticationPrincipal
注解解决方案中,Lukas Schmelzeisen是第一个提出来的。
然后您可以在控制器中使用。
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
当传入方法参数(第一个参数)时,该方法获取网络请求(第二个参数),并且如果它认为自己有责任处理该方法参数,则返回
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;
}
}
}
如果每个用户实例始终应从安全上下文中获取,但从未成为命令对象,则需要定义自定义注释。
@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,则建议使用HandlerMethodArgumentResolver而不是WebArgumentResolver。-请参见Jay的评论
对于Spring 3.1+,与HandlerMethodArgumentResolver相同
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`s answer 中有很好的描述。
只需要编写:
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
要使此功能正常工作,您需要注册
AuthenticationPrincipalArgumentResolver
(
org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
):可以通过“激活”
@EnableWebMvcSecurity
或在
mvc:argument-resolvers
中注册此bean来实现-与我上面描述的Spring 3.1解决方案相同。
请参见
Spring Security 3.2参考手册,第11.2章@AuthenticationPrincipal。
Spring-Security 4.0 解决方案
它的工作方式类似于Spring 3.2解决方案,但在Spring 4.0中,@AuthenticationPrincipal
和AuthenticationPrincipalArgumentResolver
被“移动”到另一个包中:
但是旧包中的旧类仍然存在,所以不要混淆它们!
这只是写作。
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
要使此功能正常工作,您需要注册 (
org.springframework.security.web.method.annotation.
)
AuthenticationPrincipalArgumentResolver
:通过“激活”
@EnableWebMvcSecurity
或在
mvc:argument-resolvers
中注册此bean - 与我上面描述的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