1. 概述
本教程將演示如何在 Spring Security 中檢索用户詳情。
當前已認證的用户可以通過 Spring 中多種機制訪問。我們首先介紹最常見的解決方案——編程訪問。
2. 獲取用户到 Bean
獲取當前已認證的主體最簡單的方法是使用 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. 在控制器中獲取用户
我們有額外的選項,位於一個@RestController註解的 Bean 中。
@RestController
public class GetUserWithPrincipalController {
@GetMapping(value = "/username")
public String currentUserName(Principal principal) {
return principal.getName();
}
}當然,以下是翻譯後的內容:
或者,我們還可以使用身份驗證令牌
@RestController
public class GetUserWithAuthenticationController {
@GetMapping(value = "/username")
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
}身份驗證類的API非常開放,以便框架保持最大的靈活性。因此,Spring Security principal只能作為對象檢索,並且需要將其轉換為正確的UserDetails實例。
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
System.out.println("User has authorities: " + userDetails.getAuthorities());另外,以下是直接來自 HTTP 請求的內容:
@RestController
public class GetUserWithHTTPServletRequestController {
@GetMapping(value = "/username")
public String currentUserNameSimple(HttpServletRequest request) {
Principal principal = request.getUserPrincipal();
return principal.getName();
}
}最後,我們可以使用 @AuthenticationPrincipal 註解來獲取當前已認證的用户詳細信息。
@RestController
public class GetUserWithAuthenticationPrincipalAnnotationController {
@GetMapping("/user")
public String getUser(@AuthenticationPrincipal UserDetails userDetails) {
return "User Details: " + userDetails.getUsername();
}
}此處,@AuthenticationPrincipal 註解將當前已認證用户的信息(UserDetails)注入到方法中。該註解有助於將 Authentication.getPrincipal() 解決為方法參數。
此外,當我們用 @AuthenticationPrincipal 註解標註方法參數時,Spring Security 會自動提供當前已認證用户的主體(principal)。主體代表用户的身份,可以是用户名、用户對象或任何形式的用户標識。
4. 通過自定義界面獲取用户
為了充分利用 Spring 依賴注入,並能夠在任何地方(不僅僅是在 @RestController 類型的 Bean 中)獲取認證,我們需要隱藏靜態訪問背後的簡單外觀模式:
public interface IAuthenticationFacade {
Authentication getAuthentication();
}
@Component
public class AuthenticationFacade implements IAuthenticationFacade {
@Override
public Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}外觀模式暴露 身份驗證 對象,同時隱藏靜態狀態,並保持代碼鬆散耦合和完全可測試:
@RestController
public class GetUserWithCustomInterfaceController {
@Autowired
private IAuthenticationFacade authenticationFacade;
@GetMapping(value = "/username")
public String currentUserNameSimple() {
Authentication authentication = authenticationFacade.getAuthentication();
return authentication.getName();
}
}5. 在 JSP 中獲取用户
我們可以通過利用 Spring Security Taglib 支持,從 JSP 頁面中訪問當前已認證的 principal。
首先,需要在頁面上定義標籤:
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>接下來,我們可以參考負責人。
<security:authorize access="isAuthenticated()">
authenticated as <security:authentication property="principal.username" />
</security:authorize>6. 在 Thymeleaf 中獲取用户
Thymeleaf 是一款現代的服務器端 Web 模板引擎,與 Spring MVC 框架具有良好的集成性。
讓我們看看如何在 Thymeleaf 引擎的頁面中訪問當前認證的 principal。
首先,我們需要添加 thymeleaf-spring6 和 thymeleaf-extras-springsecurity6 依賴項,以便將 Thymeleaf 與 Spring Security 集成:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
</dependency>現在,我們可以使用 HTML 頁面中的 sec:authorize 屬性引用主元素:
<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 應用中獲取用户信息的各種方法,從常用的靜態訪問機制開始,然後探討了更優的注入 principal 的方式。
http://localhost:8080/spring-security-rest-custom/foos/1