如何获取活跃用户的 UserDetails [英] How to get active user's UserDetails

查看:27
本文介绍了如何获取活跃用户的 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)从数据库加载您的自定义用户对象或
  • 想了解 HandlerMethodArgumentResolverWebArgumentResolver 如何以优雅的方式解决这个问题,或者只想了解 @AuthenticationPrincipalAuthenticationPrincipalArgumentResolver(因为它基于 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 or WebArgumentResolver can solve this in an elegant way, or just want to an learn the background behind @AuthenticationPrincipal and AuthenticationPrincipalArgumentResolver (because it is based on a HandlerMethodArgumentResolver)

然后继续阅读 - 否则只需使用 @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 中,@AuthenticationPrincipalAuthenticationPrincipalArgumentResolver 被移动"到另一个包中:

It works like the Spring 3.2 solution, but in Spring 4.0 the @AuthenticationPrincipal and AuthenticationPrincipalArgumentResolver was "moved" to an other package:

(但旧包中的旧类仍然存在,所以不要混合它们!)

(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆