Spring Boot 如何找出当前登录的用户?

Posted

技术标签:

【中文标题】Spring Boot 如何找出当前登录的用户?【英文标题】:How to find out the currently logged-in user in Spring Boot? 【发布时间】:2015-09-18 11:28:10 【问题描述】:

this Spring Boot application 中有一个 Web 服务,它为登录用户返回一些数据:

@RequestMapping("/resource")
public Map<String, Object> home() 
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("id", UUID.randomUUID().toString());
    model.put("content", "Hello World");
    return model;

想象一下,方法的返回值取决于当前登录的用户。

我怎样才能知道哪个用户以该方法登录?

【问题讨论】:

【参考方案1】:

根据要求:

使用 Spring Security internally 的 Spring Boot 提供了一个 SecurityContextHolder 类,它允许通过以下方式查找当前经过身份验证的用户:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

authentication 实例现在提供以下方法:

获取登录用户的用户名:getPrincipal() 获取认证用户的密码:getCredentials() 获取已认证用户的分配角色:getAuthorities() 获取经过身份验证的用户的更多详细信息:getDetails()

【讨论】:

或者更简单,更少干扰,如果你只对用户感兴趣,只需添加一个Principal类型的方法参数,如果你想要更多,只需添加Authentication。为您省去使用SecurityContextHolder 的麻烦。 你好我该如何使用我应该把它放在哪里来获取登录用户谢谢 @KamelMili 由于 Spring Security 通常是在输入实际应用程序逻辑之前挂起的过滤器,因此您应该能够从应用程序中的几乎任何位置访问身份验证。不确定这是否能回答您的问题 优雅(y)答案 获取登录用户的用户名:getPrincipal() => getName() ?【参考方案2】:

从 Spring Security 3.2 开始,您可以通过在控制器方法中添加参数来获取当前登录的用户(UserDetails 的实现):

import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;

@RequestMapping("/resource")
public Map<String, Object> home(@AuthenticationPrincipal User user) 
   ..

User 替换为实现UserDetails 接口的类的名称。

编辑

由于 Spring Security 4.0 注释被移动到不同的包:

import org.springframework.security.core.annotation.AuthenticationPrincipal;

附录

即使在 WebFlux 反应式环境中也可以工作,而 SecurityContextHolder.getContext().getAuthentication() 由于范式从每个请求的线程模型转变为每个线程的多个请求而无法工作。

【讨论】:

这总是返回 null,即使 Authentication auth = SecurityContextHolder.getContext().getAuthentication();返回一个用户 @DanielMethner 这不应该发生我在 Webflux 和非 Webflux 环境的控制器中使用它,它在任何地方都可以使用。您能否打开一个新问题并将您的配置、spring 版本和控制器发布到它不起作用的地方,我会看看吗? 我忘记发送身份验证标头。问题因此得到解决。无论如何,谢谢! 当我使用 @AuthenticationPrincipal UserDetailsImpl user 时不为空并且可以正常工作。这适用于使用User以外的主体的单独类的人【参考方案3】:

您也可以简单地使用HttpServletRequest来获取用户原则,

使用 HttpServletRequest 请求,

String user=request.getUserPrincipal().getName();

【讨论】:

【参考方案4】:

一种方法是添加java.security.Principal作为参数,如下所示:

@RequestMapping("/resource")
public Map<String, Object> home(Principal principal) 
    Map<String, Object> model = new HashMap<String, Object>();
    model.put("id", UUID.randomUUID().toString());
    model.put("content", "Hello " + principal.getName());
    return model;

【讨论】:

【参考方案5】:

从5.2版本开始可以使用CurrentSecurityContext注解:

@GetMapping("/hello")
public String hello(@CurrentSecurityContext(expression="authentication?.name")
                    String username) 
    return "Hello, " + username + "!";

【讨论】:

authentication?.name 以避免在不存在身份验证时出现空指针 @JustinasJakavonis 好点!我编辑答案。谢谢【参考方案6】:

在 Spring boot v2.1.9.RELEASE 中,如果您尝试获取 name、email 和 given_name,您可以从 Pricipal 获取这些详细信息。 注意:我正在使用带有 google oauth2 的 spring security

Map<String , Object> userDetails = ((DefaultOidcUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAttributes(); System.out.println(userDetails.get("name")); System.out.println(userDetails.get("email")); System.out.println(userDetails.get("given_name"));

【讨论】:

【参考方案7】:

最近使用Keycloak认证服务器,访问当前登录的用户数据可以这样访问

String userID;

KeycloakPrincipal kcPrincipal = getPrincipal();
KeycloakSecurityContext ksContext = kcPrincipal.getKeycloakSecurityContext();
IDToken idToken = ksContext.getToken();
userID = idToken.getName();

【讨论】:

【参考方案8】:

我正在使用带有 OAuth 的 Spring Boot 2.0,所以我正在这样做

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Object pricipal = auth.getPrincipal();
String user="";
if (pricipal instanceof DefaultOidcUser) 
       user = ((DefaultOidcUser) pricipal).getName();

【讨论】:

如何在 JSP 中获取 getName 和 getAttribute?【参考方案9】:

你可以在不使用任何spring安全特性的情况下找到当前登录的用户名。 您只需要一个 jdk 1.8

执行以下操作:

@RequestMapping("/login")
@Override
public ModelAndView AuthChecker(@RequestParam("email") String email, @RequestParam("password") String password, Customers cust) 

     ModelAndView mv = new ModelAndView("index");
     if((repo.findByEmail(email)!=null) && (repo.findByPassword(password)!=null)) 
        
         
      List<Customers> l=  repo.findAll();
      
      cust = (Customers) l.stream() 
      .filter(x -> email.equals(x.getEmail()))        
      .findAny()                                      
      .orElse(null); 
    
        mv.addObject("user",cust.getName());
         mv.setViewName("DashBoardRedirect");
    
         return mv;

成功获取名称后,您可以在任何 jsp/thymeleaf 视图中使用相同的名称。

【讨论】:

以上是关于Spring Boot 如何找出当前登录的用户?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Keycloak 在 Spring Boot 中获取当前登录用户?

Spring Boot - 确保数据属于当前登录用户

用户登录时的 Spring Boot 安全自定义消息

Spring Boot WebSockets 无法找到当前用户(主体)

在 Spring-boot 中成功登录后如何限制 POST Rest Api 以供公共访问

当用户使用 Spring Boot 登录失败时,如何在登录页面中显示错误消息?