我有一个使用Spring Security的Spring MVC web应用程序。我想知道当前登录用户的用户名。我正在使用下面给出的代码片段。这是公认的方式吗?

我不喜欢在这个控制器中调用静态方法——恕我直言,这违背了Spring的全部目的。有没有一种方法来配置应用程序有当前的SecurityContext,或当前的认证,注入代替?

  @RequestMapping(method = RequestMethod.GET)
  public ModelAndView showResults(final HttpServletRequest request...) {
    final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
    ...
  }

当前回答

The only problem is that even after authenticating with Spring Security, the user/principal bean doesn't exist in the container, so dependency-injecting it will be difficult. Before we used Spring Security we would create a session-scoped bean that had the current Principal, inject that into an "AuthService" and then inject that Service into most of the other services in the Application. So those Services would simply call authService.getCurrentUser() to get the object. If you have a place in your code where you get a reference to the same Principal in the session, you can simply set it as a property on your session-scoped bean.

其他回答

我同意必须为当前用户查询SecurityContext很糟糕,这似乎是一种非常非spring的处理这个问题的方式。

我写了一个静态的“助手”类来处理这个问题;它是脏的,因为它是一个全局和静态的方法,但我认为如果我们改变任何与安全相关的东西,至少我只需要改变一个地方的细节:

/**
* Returns the domain User object for the currently logged in user, or null
* if no User is logged in.
* 
* @return User object for the currently logged in user, or null if no User
*         is logged in.
*/
public static User getCurrentUser() {

    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal()

    if (principal instanceof MyUserDetails) return ((MyUserDetails) principal).getUser();

    // principal object is either null or represents anonymous user -
    // neither of which our domain User object can represent - so return null
    return null;
}


/**
 * Utility method to determine if the current user is logged in /
 * authenticated.
 * <p>
 * Equivalent of calling:
 * <p>
 * <code>getCurrentUser() != null</code>
 * 
 * @return if user is logged in
 */
public static boolean isLoggedIn() {
    return getCurrentUser() != null;
}

我使用@Controller类中的@AuthenticationPrincipal注释以及@ controlleradvisor注释。例:

@ControllerAdvice
public class ControllerAdvicer
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAdvicer.class);


    @ModelAttribute("userActive")
    public UserActive currentUser(@AuthenticationPrincipal UserActive currentUser)
    {
        return currentUser;
    }
}

其中UserActive是我用于已登录用户服务的类,并且扩展自org.springframework.security.core.userdetails.User。喜欢的东西:

public class UserActive extends org.springframework.security.core.userdetails.User
{

    private final User user;

    public UserActive(User user)
    {
        super(user.getUsername(), user.getPasswordHash(), user.getGrantedAuthorities());
        this.user = user;
    }

     //More functions
}

真的很容易。

我得到认证的用户 HttpServletRequest.getUserPrincipal ();

例子:

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.support.RequestContext;

import foo.Form;

@Controller
@RequestMapping(value="/welcome")
public class IndexController {

    @RequestMapping(method=RequestMethod.GET)
    public String getCreateForm(Model model, HttpServletRequest request) {

        if(request.getUserPrincipal() != null) {
            String loginName = request.getUserPrincipal().getName();
            System.out.println("loginName : " + loginName );
        }

        model.addAttribute("form", new Form());
        return "welcome";
    }
}

对于我写的上一个Spring MVC应用程序,我没有注入SecurityContext holder,但我确实有一个基本控制器,我有两个实用程序方法与此相关…isAuthenticated() & getUsername()。在内部,它们执行您所描述的静态方法调用。

至少在以后需要重构时,它只在一个地方。

为了让它只显示在JSP页面中,你可以使用Spring Security标签库:

http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html

要使用任何标记,必须在JSP中声明安全标记库:

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

然后在jsp页面中执行如下操作:

<security:authorize access="isAuthenticated()">
    logged in as <security:authentication property="principal.username" /> 
</security:authorize>

<security:authorize access="! isAuthenticated()">
    not logged in
</security:authorize>

注意:正如@SBerg413在评论中提到的,您需要添加

use-expressions = " true "

到security.xml配置中的“http”标签以使其工作。