如何获取活动用户的UserDetails [英] How to get active user's UserDetails
问题描述
在我的控制器中,当我需要活动(登录)用户时,我正在执行以下操作来获取 UserDetails
实现:
In my controllers, when I need the active (logged in) user, I am doing the following to get my UserDetails
implementation:
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());
它工作正常,但我认为Spring可以在这样的情况下让生活更轻松。有没有办法让 UserDetails
自动装入控制器或方法?
It works fine, but I would think Spring could make life easier in a case like this. Is there a way to have the UserDetails
autowired into either the controller or the method?
例如,像:
public ModelAndView someRequestHandler(Principal principal) { ... }
但是我没有得到 UsernamePasswordAuthenticationToken
,而是获得 UserDetails
相反?
But instead of getting the UsernamePasswordAuthenticationToken
, I get a UserDetails
instead?
我正在寻找一个优雅的解决方案。任何想法?
I'm looking for an elegant solution. Any ideas?
推荐答案
序言:自Spring-Security 3.2以来,有一个很好的注释 @AuthenticationPrincipal
在本答案结尾处描述。当你使用Spring-Security> = 3.2时,这是最好的方法。
Preamble: Since Spring-Security 3.2 there is a nice annotation @AuthenticationPrincipal
described at the end of this answer. This is the best way to go when you use Spring-Security >= 3.2.
当你:
- 使用旧版本的Spring-Security,
- 需要通过存储在数据库中的一些信息(如登录名或ID)从数据库加载自定义用户对象校长或
- 想了解
HandlerMethodArgumentResolver
或WebArgumentResolver
如何解决这个问题以优雅的方式,或者只是想了解@AuthenticationPrincipal
和AuthenticationPrincipalArgumentResolver
背后的背景(因为它基于aHandlerMethodArgumentResolver
)
- use an older version of Spring-Security,
- need to load your custom User Object from the Database by some information (like the login or id) stored in the principal or
- want to learn how a
HandlerMethodArgumentResolver
orWebArgumentResolver
can solve this in an elegant way, or just want to an learn the background behind@AuthenticationPrincipal
andAuthenticationPrincipalArgumentResolver
(because it is based on aHandlerMethodArgumentResolver
)
然后继续阅读 - 否则只需使用 @AuthenticationPrincipal
并感谢Rob Winch( @AuthenticationPrincipal
的作者)和 Lukas Schmelzeisen (答案)。
then keep on reading — else just use @AuthenticationPrincipal
and thank to Rob Winch (Author of @AuthenticationPrincipal
) and Lukas Schmelzeisen (for his answer).
(顺便说一句:我的回答有点老了(1月) 2012),所以 Lukas Schmelzeisen 作为第一个出现在 @AuthenticationPrincipal
基于Spring Security 3.2的注释解决方案。)
(BTW: My answer is a bit older (January 2012), so it was Lukas Schmelzeisen that come up as the first one with the @AuthenticationPrincipal
annotation solution base on Spring Security 3.2.)
然后你可以使用你的控制器
Then you can use in your controller
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
如果你需要一次就可以了。但是如果你需要它几次丑陋,因为它会污染你的控制器的基础设施细节,通常应该被框架隐藏。
That is ok if you need it once. But if you need it several times its ugly because it pollutes your controller with infrastructure details, that normally should be hidden by the framework.
所以你真正想要的是有一个像这样的控制器:
So what you may really want is to have a controller like this:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
因此你只需要实现一个 WebArgumentResolver
。它有一个方法
Therefore you only need to implement a WebArgumentResolver
. It has a method
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
获取Web请求(第二个参数)并且必须返回用户
如果它感觉负责方法参数(第一个参数)。
That gets the web request (second parameter) and must return the User
if its feels responsible for the method argument (the first parameter).
从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实例都应该从安全上下文中获取,但是永远不是命令对象,则可以跳过它。
You need to define the Custom Annotation -- You can skip it if every instance of User should always be taken from the security context, but is never a command object.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
在配置中你只需要添加:
In the configuration you only need to add this:
<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,他们会在WebArgumentResolver上推荐HandlerMethodArgumentResolver。 - 查看Jay的评论
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;
}
}
}
在配置中,您需要添加此
In the configuration, you need to add this
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@See 利用Spring MVC 3.1 HandlerMethodArgumentResolver接口
Spring Security 3.2(不要与Spring 3.2混淆)有自己的内置版本解决方案: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
)。这在 Lukas Schmelzeisen的回答中有详细描述。
Spring Security 3.2 (do not confuse with Spring 3.2) has own build in solution: @AuthenticationPrincipal
(org.springframework.security.web.bind.annotation.AuthenticationPrincipal
) . This is nicely described in 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解决方案一样。
To get this working you need to register the AuthenticationPrincipalArgumentResolver
(org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
) : either by "activating" @EnableWebMvcSecurity
or by registering this bean within mvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.
@参见 Spring Security 3.2参考,第11.2章。 @AuthenticationPrincipal
它与Spring 3.2解决方案类似,但在Spring 4.0中 @AuthenticationPrincipal
和 AuthenticationPrincipalArgumentResolver
被移动到另一个包裹:
It works like the Spring 3.2 solution, but in Spring 4.0 the @AuthenticationPrincipal
and AuthenticationPrincipalArgumentResolver
was "moved" to an other package:
-
org.springframework.security.core.annotation。 AuthenticationPrincipal
-
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
org.springframework.security.core.annotation.AuthenticationPrincipal
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
(但旧包中的旧类仍然存在,所以不要混合它们!)
(But the old classes in its old packges still exists, so do not mix them!)
这只是写作
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 Spring 3.1解决方案一样。
To get this working you need to register the (org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: either by "activating" @EnableWebMvcSecurity
or by registering this bean within mvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@See Spring Security 5.0参考,第39.3章@AuthenticationPrincipal
这篇关于如何获取活动用户的UserDetails的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!