Java 如何获得活动用户';用户详细信息
在我的控制器中,当我需要活动(登录)用户时,我将执行以下操作以获取我的Java 如何获得活动用户';用户详细信息,java,spring,spring-mvc,spring-security,Java,Spring,Spring Mvc,Spring Security,在我的控制器中,当我需要活动(登录)用户时,我将执行以下操作以获取我的UserDetails实现: User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); log.debug(activeUser.getSomeCustomField()); 它工作得很好,但我认为在这种情况下,春天可以让生活变得更轻松。是否有办法将UserDetails自动连接到控制器或方法中
UserDetails
实现:
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());
它工作得很好,但我认为在这种情况下,春天可以让生活变得更轻松。是否有办法将UserDetails
自动连接到控制器或方法中
例如,类似于:
public ModelAndView someRequestHandler(Principal principal) { ... }
但是我没有得到用户名密码身份验证令牌
,而是得到了用户详细信息
我在寻找一个优雅的解决方案。有什么想法吗?Spring安全性旨在与其他非Spring框架协同工作,因此它没有与Spring MVC紧密集成。默认情况下,Spring Security从
HttpServletRequest.getUserPrincipal()
方法返回Authentication
对象,这就是作为主体得到的。通过使用,您可以直接从中获取UserDetails
对象
UserDetails ud = ((Authentication)principal).getPrincipal()
还请注意,对象类型可能因所使用的身份验证机制而异(例如,您可能无法获得UsernamePasswordAuthenticationToken
),并且身份验证
不必严格包含UserDetails
。它可以是字符串或任何其他类型
如果您不想直接调用SecurityContextHolder
,最优雅的方法(我将遵循)是注入您自己的定制安全上下文访问器接口,该接口是定制的,以满足您的需求和用户对象类型。使用相关方法创建接口,例如:
interface MySecurityAccessor {
MyUserDetails getCurrentUser();
// Other methods
}
然后,您可以通过访问标准实现中的SecurityContextHolder
来实现这一点,从而将代码与Spring安全性完全分离。然后将其注入需要访问安全信息或当前用户信息的控制器
另一个主要好处是,使用固定数据进行简单的实现以进行测试很容易,而不必担心填充线程局部变量等等。序言:自Spring Security 3.2以来,有一个很好的注释
@AuthenticationPrincipal
。当您使用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) {
...
}
因此,您只需要实现一个。它有一个方法
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
它获取web请求(第二个参数),如果它认为对方法参数(第一个参数)负责,则必须返回用户
从Spring3.1开始,有一个新概念叫做。如果您使用Spring 3.1+,那么您应该使用它。(答案的下一节将对此进行描述)
您需要定义自定义注释——如果用户的每个实例都应该始终从安全上下文中获取,但决不是命令对象,则可以跳过它
@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>
在配置中,您需要添加以下内容
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
要使其正常工作,您需要注册
AuthenticationPrincipalArgumentResolver
(org.springframework.security.web.bind.support.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 4.0解决方案
它的工作原理与Spring 3.2解决方案类似,但在Spring 4.0中,
@AuthenticationPrincipal
和AuthenticationPrincipalArgumentResolver
被“移动”到另一个包中:
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
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>
@请参见实现
HandlerInterceptor
接口,然后将UserDetails
注入到具有模型的每个请求中,如下所示:
@Component
public class UserInterceptor implements HandlerInterceptor {
....other methods not shown....
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if(modelAndView != null){
modelAndView.addObject("user", (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal());
}
}
虽然提供了一个优雅的解决方案,但使用SpringSecurity3.2,您不再需要实现自己的ArgumentResolver
如果您有一个UserDetails
实现CustomUser
,您可以执行以下操作:
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {
// .. find messages for this User and return them...
}
请参见从Spring Security 3.2版开始,一些旧版本的答案已经实现了自定义功能
@Controller
public abstract class AbstractController {
@ModelAttribute("loggedUser")
public User getLoggedUser() {
return (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {
// .. find messages for this User and return them...
}
@Controller
public class MyController {
@RequestMapping("/user/current/show")
public String show(@AuthenticationPrincipal CustomUser customUser) {
// do something with CustomUser
return "view";
}
}
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<sec:authentication property="principal.yourCustomField"/>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring-security.version}</version>
</dependency>
@GetMapping(value = "/mappingEndPoint") <ReturnType> methodName(Authentication auth) {
String userName = auth.getName();
return <ReturnType>;
}