如何获取活跃用户的 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
(因为它基于HandlerMethodArgumentResolver
)
- 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).
(顺便说一句:我的回答有点旧(2012 年 1 月),所以 Lukas Schmelzeisen作为第一个基于 Spring Security 3.2 的 @AuthenticationPrincipal
注释解决方案.)
(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
它获取网络请求(第二个参数),如果它认为对方法参数(第一个参数)负责,则必须返回 User
.
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,他们建议使用 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;
}
}
}
在配置中,需要添加这个
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.1HandlerMethodArgumentResolver 接口
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.
@See 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
(但旧包中的旧类仍然存在,所以不要混合它们!)
(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 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屋!