Spring Security - 在Controllers中获取登录用户 - 礼貌

时间:2014-09-07 18:16:21

标签: java spring spring-mvc spring-security

我正在使用Spring(4.0.2),Spring @MVC(4.0.2)和Spring Security(3.2.5)开发我的第一个应用程序。我现在能够使用Spring Security成功登录,但现在可以使用#34;良好实践"我已经想到了一个问题:

目前我已经实现了我自己的UserDetailsUserDetailsService版本,以便保存从数据库中提取的详细信息。

获取UserDetails的最佳方法(清洁工)是什么?

到目前为止,我正在使用这两种选择:

  1. 使用方法中的下一个代码行

    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    
  2. 添加参数Authentication auth和方法

    中的下一行
    User user = ((CurrentUserDetails) auth.getPrincipal()).getCurrentUser();
    
  3. 我的印象是我弄脏了代码。你不这么认为吗?

2 个答案:

答案 0 :(得分:5)

在我参与的每个项目中,我们始终使用至少以下方法实现SecurityUtils类:

/**
 * Get the active authentication object.
 * @param strict Whether to throw an exception if no authentication object is found.
 * @return Authentication object. Can be null only in non-strict mode.
 */
public static Authentication getAuthentication(boolean strict) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (strict && authentication == null) {
        throw new AuthenticationCredentialsNotFoundException("Missing authentication object.");
    }
    return authentication;
}

/**
 * Get active person principal.
 * @return Active person principal user. Never null.
 * @throws AccessDeniedException in case there is no active person principal.
 */
public static PersonPrincipal getActivePersonPrincipal() {
    Object principal = getAuthentication(true).getPrincipal();
    if (!(principal instanceof PersonPrincipal)) {
        throw new AccessDeniedException("Invalid principal '" + principal + "'.");
    }
    return (PersonPrincipal) principal;
}

此课程通常位于{projectPackage}.core.security个包中。只要任何代码需要访问当前用户,它就会调用此类。

此外,我们永远不会让控制器层告诉服务层有关身份验证的任何信服务层(甚至是Hibernate事件监听器)总是向SecurityUtils询问当前的身份验证。

答案 1 :(得分:2)

Spring Security能够将Authentification置于可以使用HttpServletRequest.getUserPrincipal()检索的请求中。在Spring MVC中,控制器只需将其作为参数传递即可访问主体。

因此,恕我直言,从控制器访问登录用户的简单方法之一是:

@RequestMapping(...)
public String method(Principal principal, ...) {
    Authentication auth = (Authentication) principal;
    ...
}

编辑(每条评论):

如果您不想在每个控制器方法上重复代码,您可以:

  • 使用@ModelAttribute方法在一个位置使用登录用户填充模型(主要是在视图中使用它)
  • 将其放入请求范围的bean中,并通过AOP范围代理将其直接注入控制器。