1. 概述
本文将讲解如何在Spring Security中获取当前用户信息。
Spring中有多种方式可以获取当前登录用户(authenticated principal),让我们先介绍最常见的 —— 手动编码的方式。
2. 从SecurityContextHolder中获取User
最简单方式是通过调用SecurityContextHolder的静态方法
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();
这里还需要改进下,获取用户信息之前需要先检测是否已登录认证了:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof AnonymousAuthenticationToken)) {
String currentUserName = authentication.getName();
return currentUserName;
}
当然,通过静态方法调用有些弊端 —— 最明显的是降低了代码可测性。下面我们介绍其他方法。
3. 从Controller中获取User
在Controller
方法中有几种方式可以获取,我们可以将Principal
作为参数,Spring框架会自动为我们赋值。
@Controller
public class GetUserWithPrincipalController {
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserName(Principal principal) {
return principal.getName();
}
}
另外, 我们也可以将Authentication作为参数:
@Controller
public class GetUserWithAuthenticationController {
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
}
为了尽可能保持灵活性,Authentication
接口设计的非常开放。因此, getPrincipal()
方法返回的是Object
类型,需要我们正确的转换为UserDetails
实例。
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
System.out.println("User has authorities: " + userDetails.getAuthorities());
也可直接 从HTTP request中获取:
@Controller
public class GetUserWithHTTPServletRequestController {
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserNameSimple(HttpServletRequest request) {
Principal principal = request.getUserPrincipal();
return principal.getName();
}
}
最后,我们也可以 通过@AuthenticationPrincipal
注解方式获取UserDetails
实例:
@RestController
public class GetUserWithAuthenticationPrincipalAnnotationController {
@GetMapping("/user")
public String getUser(@AuthenticationPrincipal UserDetails userDetails) {
return "User Details: " + userDetails.getUsername();
}
}
4. 通过自定义接口方式获取User
为了充分利用Spring依赖注入,并使我们可以在任何位置获取User
(而不只是在@Controller bean中),我们可以自定义一个@Component
并结合第一种静态方法方式实现:
public interface IAuthenticationFacade {
Authentication getAuthentication();
}
@Component
public class AuthenticationFacade implements IAuthenticationFacade {
@Override
public Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
我们自定义的AuthenticationFacade
提供了访问Authentication
对象的方法,同时隐藏了静态方法调用细节,让业务解耦并方便测试:
@Controller
public class GetUserWithCustomInterfaceController {
@Autowired
private IAuthenticationFacade authenticationFacade;
@RequestMapping(value = "/username", method = RequestMethod.GET)
@ResponseBody
public String currentUserNameSimple() {
Authentication authentication = authenticationFacade.getAuthentication();
return authentication.getName();
}
}
5. JSP中获取User
同样我们可以在JSP页面中获取当前登录用户,利用spring security taglib
支持。首先需要在页面中定义标签:
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
然后,我们可以引用principal
:
<security:authorize access="isAuthenticated()">
authenticated as <security:authentication property="principal.username" />
</security:authorize>
6. Thymeleaf中获取User
Thymeleaf是一款现代的, 服务端HTML渲染模板引擎, 与Spring MVC具有良好的集成。下面看下如何在Thymeleaf
中获取User
。
首先为了集成Thymeleaf
与Spring Security
,我们需要添加thymeleaf-spring5 与 thymeleaf-extras-springsecurity5 依赖:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
现在我们可以在HTML中使用sec:authorize
属性引用principal
:
<html xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<body>
<div sec:authorize="isAuthenticated()">
Authenticated as <span sec:authentication="name"></span></div>
</body>
</html>
7. 总结
本文我们讲解了如何在Spring应用中获取当前登录用户信息,开始使用静态方法的方式获取,后面介绍了几种更好的方式,通过注解注入的方式。
惯例,本文完整源代码可从GitHub上获取。这是一个基于Eclipse的项目,所以应该很容易导入和运行。项目运行后,访问主页http://localhost:8080/spring-security-rest-custom/foos/1