序言:自 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 月),所以 Lukas Schmelzeisen 是第一个使用基于 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 请求(第二个参数),如果它认为对方法参数(第一个参数)负责,则必须返回 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>
@见:Learn to customize Spring MVC @Controller method arguments
需要注意的是,如果你使用的是 Spring 3.1,他们推荐 HandlerMethodArgumentResolver 而不是 WebArgumentResolver。 - 见 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>
@见Leveraging the Spring MVC 3.1 HandlerMethodArgumentResolver interface
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 - 与我在 May Spring 3.1 解决方案中描述的方式相同以上。
@见Spring Security 3.2 Reference, Chapter 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 - 与我在 May 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 Reference, Chapter 39.3 @AuthenticationPrincipal