在我的控制器中,当我需要活动(登录)用户时,我正在执行以下操作来获得我的UserDetails实现:
UserDetails
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); log.debug(activeUser.getSomeCustomField());
它工作得很好,但我认为 Spring 在这种情况下可以让生活更轻松。有没有办法将UserDetails自动连接到控制器或方法中?
例如,类似:
public ModelAndView someRequestHandler(Principal principal) { ... }
但是UsernamePasswordAuthenticationToken我没有得到 ,而是得到了 a UserDetails?
UsernamePasswordAuthenticationToken
我正在寻找一个优雅的解决方案。有任何想法吗?
序言:@AuthenticationPrincipal自 Spring-Security 3.2 以来,此答案的末尾描述了一个很好的注释。当您使用 Spring-Security >= 3.2 时,这是最好的方法。
@AuthenticationPrincipal
当你:
HandlerMethodArgumentResolver
WebArgumentResolver
AuthenticationPrincipalArgumentResolver
然后你可以在你的控制器中使用
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是否对方法参数(第一个参数)负责。
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>
@See:学习自定义 Spring MVC @Controller 方法参数
应该注意的是,如果您使用的是 Spring 3.1,他们建议使用 HandlerMethodArgumentResolver 而不是 WebArgumentResolver。 - 见杰伊的评论
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 3.2 混淆)有自己的内置解决方案:@AuthenticationPrincipal( org.springframework.security.web.bind.annotation.AuthenticationPrincipal) 。这在Lukas Schmelzeisen 的回答中得到了很好的描述
org.springframework.security.web.bind.annotation.AuthenticationPrincipal
它只是在写
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) { ... }
要使其正常工作,您需要注册AuthenticationPrincipalArgumentResolver( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver) :通过“激活” @EnableWebMvcSecurity或通过在其中注册此 bean mvc:argument-resolvers- 与我在上面的 May Spring 3.1 解决方案中描述的方式相同。
org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
@EnableWebMvcSecurity
mvc:argument-resolvers
@参见Spring Security 3.2 参考,第 11.2 章。@AuthenticationPrincipal
它的工作方式类似于 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:通过“激活” @EnableWebMvcSecurity或通过在其中注册此 bean mvc:argument-resolvers- 与我在上面的 May Spring 3.1 解决方案中描述的方式相同。
org.springframework.security.web.method.annotation.
<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