我有一个使用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,并且需要在控制器中使用经过身份验证的主体,那么最好的解决方案是这样做:

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

    @Controller
    public class KnoteController {
        @RequestMapping(method = RequestMethod.GET)
        public java.lang.String list(Model uiModel, UsernamePasswordAuthenticationToken authToken) {

            if (authToken instanceof UsernamePasswordAuthenticationToken) {
                user = (User) authToken.getPrincipal();
            }
            ...

    }

其他回答

我使用@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
}

真的很容易。

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

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

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

将Principal定义为控制器方法中的依赖项,spring将在调用时将当前已验证的用户注入到方法中。

如果您正在使用Spring Security ver >= 3.2,您可以使用@AuthenticationPrincipal注释:

@RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(@AuthenticationPrincipal CustomUser currentUser, HttpServletRequest request) {
    String currentUsername = currentUser.getUsername();
    // ...
}

这里,CustomUser是一个自定义对象,它实现了由自定义UserDetailsService返回的UserDetails。

更多信息可以在Spring Security参考文档的@AuthenticationPrincipal一章中找到。

在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) {
  ...
}