【问题标题】:HandlerMethodArgumentResolver implementation returns an empty user objectHandlerMethodArgumentResolver 实现返回一个空的用户对象
【发布时间】:2015-02-11 17:30:09
【问题描述】:

我创建了一个HandlerMethodArgumentResolver 的实现,以返回当前登录的用户,用于使用@CurrentUser 注释的控制器方法。但是,当调用HandlerMethodArgumentResolverresolveArgument 方法时,会返回一个空用户。我已验证我的自定义 UserDetailsService 实现确实检索了完整的用户对象。

我使用的代码如下。

@CurrUser 注释:

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {
}

空用户的 HandlerMethodArgumentResolver 实现:

public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Inject
    private UserService userService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(CurrentUser.class) != null
                  && parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        if (this.supportsParameter(parameter)) {
            Principal principal = webRequest.getUserPrincipal();
            User user = (User) ((Authentication) principal).getPrincipal(); // This user is empty!!!
            return user;
        } else {
            return WebArgumentResolver.UNRESOLVED;
        }
    }
}

调用Controller方法:

@RequestMapping(value = "/user", method = RequestMethod.GET)
public HttpEntity<Resource<User>> currentUser(@CurrentUser User self) {

    log.debug("CurrentUserController > currentUser GET> " + self);
}

检索填充用户的 UserDetailsS​​ervice 的 loadUserByUsername(我验证了它是第一个调用的):

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = userService.findByUsername(username);
    CustomUserDetails ud = new CustomUserDetails(user);
    return ud;
}

WebMvcConfigurerAdapter 配置:

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(currentUserMethodArgumentResolver());
}

@Bean
public CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {
    return new CurrentUserMethodArgumentResolver();
}

【问题讨论】:

  • 您实施自己的方法有什么原因吗?您可以随时注入 Principal,这是 Spring MVC 开箱即用的支持,Spring Security 已经拥有 @AuthenticationPrincipal
  • 另外,当使用 @AuthenticationPrincipal 作为元注释时,Spring Security 中的 HandlerMethodArgumentResolver 仍然有效,因此无需自己实现。
  • 我的初衷是提供一个“扩展的”用户对象,该对象将填充数据库中的其他数据。我认为最好从一段代码中检索额外信息,而不是在整个服务实现中查询数据。正如您可能建议的那样,我可能会让事情变得比需要的更复杂一些。我会看看你的建议,看看它是否能完成这项工作。谢谢@M。 Deinum 的信息。
  • @AuthenticationPrincipal 只是检索当前的UserDetails,从您发布的内容中我可以看出,它是您的扩展用户对象。

标签: spring-mvc spring-security


【解决方案1】:

我发现了问题所在 - 问题在于我如何实现“CustomUserDetails”:

public static class CustomUserDetails extends User implements UserDetails {

    ...

}

我正在扩展我的自定义用户类并实现UserDetails。我不知道为什么,但 Spring 不喜欢这样。此后,我通过创建和填充新的org.springframework.security.core.userdetails.User 并将其从对 `loadUserByUsername' 的调用中返回来修复了代码。

【讨论】:

    猜你喜欢
    • 2021-03-31
    • 2014-07-15
    • 2018-08-25
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多