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

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

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

当前回答

在Spring 3+中,您有以下选项。

方案一:

@RequestMapping(method = RequestMethod.GET)    
public String currentUserNameByPrincipal(Principal principal) {
    return principal.getName();
}

选择二:

@RequestMapping(method = RequestMethod.GET)
public String currentUserNameByAuthentication(Authentication authentication) {
    return authentication.getName();
}

选项3:

@RequestMapping(method = RequestMethod.GET)    
public String currentUserByHTTPRequest(HttpServletRequest request) {
    return request.getUserPrincipal().getName();

}

选项4:花哨的一个:查看更多细节

public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
  ...
}

其他回答

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.

在Spring 3+中,您有以下选项。

方案一:

@RequestMapping(method = RequestMethod.GET)    
public String currentUserNameByPrincipal(Principal principal) {
    return principal.getName();
}

选择二:

@RequestMapping(method = RequestMethod.GET)
public String currentUserNameByAuthentication(Authentication authentication) {
    return authentication.getName();
}

选项3:

@RequestMapping(method = RequestMethod.GET)    
public String currentUserByHTTPRequest(HttpServletRequest request) {
    return request.getUserPrincipal().getName();

}

选项4:花哨的一个:查看更多细节

public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
  ...
}

您可以使用Spring AOP方法。 例如,如果你有一些服务,它需要知道当前的本金。您可以引入自定义注释,例如@Principal,它表明该服务应该是依赖于主体的。

public class SomeService {
    private String principal;
    @Principal
    public setPrincipal(String principal){
        this.principal=principal;
    }
}

然后在您的通知中,我认为需要扩展MethodBeforeAdvice,检查特定的服务有@Principal注释并注入Principal名称,或者将其设置为'ANONYMOUS'。

如果你正在使用Spring 3,最简单的方法是:

 @RequestMapping(method = RequestMethod.GET)   
 public ModelAndView showResults(final HttpServletRequest request, Principal principal) {

     final String currentUser = principal.getName();

 }

Yes, statics are generally bad - generally, but in this case, the static is the most secure code you can write. Since the security context associates a Principal with the currently running thread, the most secure code would access the static from the thread as directly as possible. Hiding the access behind a wrapper class that is injected provides an attacker with more points to attack. They wouldn't need access to the code (which they would have a hard time changing if the jar was signed), they just need a way to override the configuration, which can be done at runtime or slipping some XML onto the classpath. Even using annotation injection in the signed code would be overridable with external XML. Such XML could inject the running system with a rogue principal. This is probably why Spring is doing something so un-Spring-like in this case.