Học viên : Nguyễn Thu Hằng (Java 08)
Email : 14thuhang@gmail.com
Bài viết gốc : https://www.baeldung.com/get-user-in-spring-security

1. Mở đầu

Bài viết này sẽ chỉ ra cách lấy thông tin người dùng trong Spring Security.

Thông tin người dùng đã được xác thực có thể lấy thông qua một số cơ chế có sẵn trong Spring. Trước tiên, hãy đề cập đến giải pháp phổ biến nhất.

2. Lấy thông tin user trong Bean

Cách đơn giản nhất để lấy thông tin người dùng đã được xác thực là thông qua SecurityContextHolder:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();

Hoặc bạn có thể kiểm tra xem người dùng đã xác thực hay không trước khi lấy ra thông tin người dùng như sau :

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof AnonymousAuthenticationToken)) {
    String currentUserName = authentication.getName();
    return currentUserName;
}

Tuy nhiên có vài nhược điểm khi dùng theo cách này và khả năng kiểm tra không cao, chúng ta sẽ tìm hiểu thêm các giải pháp thay thế cho cách này ở phần dưới .

3. Lấy thông tin user trong Controller

Chúng tôi có các tùy chọn bổ sung trong bean có chú thích @Controller.

Chúng ta có thể xác định principal trực tiếp dưới dạng parameter của phương thức và nó sẽ được giải quyết chính xác bởi framework:

@Controller
public class SecurityController {

    @RequestMapping(value = "/username", method = RequestMethod.GET)
    @ResponseBody
    public String currentUserName(Principal principal) {
        return principal.getName();
    }
}

Ngoài ra, chúng tôi cũng có thể sử dụng authentication token:

@Controller
public class SecurityController {

    @RequestMapping(value = "/username", method = RequestMethod.GET)
    @ResponseBody
    public String currentUserName(Authentication authentication) {
        return authentication.getName();
    }
}

API của class Authentication linh hoạt và rất dễ sử dụng. Chính vì lý do này, Spring Security principal chỉ có thể được nhận dưới dạng Object và chúng ta cần convert sang đối tượng UserDetails

UserDetails userDetails = (UserDetails) authentication.getPrincipal();
System.out.println("User has authorities: " + userDetails.getAuthorities());

Cuối cùng là gọi trực tiếp từ 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();
    }
}

4. Lấy thông user thông qua Custom Interface

Để tận dụng hoàn toàn Spring dependency injection và có thể truy xuất thông tin xác thực ở mọi nơi, không chỉ ở trong @Controller bean, chúng ta sử dụng Custom Interface

public interface IAuthenticationFacade {
    Authentication getAuthentication();
}
@Component
public class AuthenticationFacade implements IAuthenticationFacade {

    @Override
    public Authentication getAuthentication() {
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

Method trả về đối tượng Authentication trong khi ẩn static access và giữ cho code được tách riêng và hoàn toàn có thể kiểm tra:

@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. Lấy ra user trong JSP

Thông tin người dùng đã xác thực có thể được truy cập trong JSP Pages bằng cách sử dụng Spring Security Taglib

Đầu tiên, chúng ta cần xác định thẻ trong Page :

<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

Tiếp theo, chúng ta có thể gọi đến principal :

<security:authorize access="isAuthenticated()">
    authenticated as <security:authentication property="principal.username" /> 
</security:authorize>

6. Lấy ra thông tin user trong Thymeleaf

Thymeleaf là một server-side web templating engine hiện đại, tích hợp tốt với Spring MVC framework.

Hãy xem làm thế nào để truy cập thông tin người dùng đã xác thực trong một trang với Thymeleaf engine.

Đầu tiên, chúng ta cần dependency thymeleaf-spring5thymeleaf-extras-springecurity5 để tích hợp Thymeleaf với Spring Security:

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>

Bây giờ chúng ta có thể tham chiếu đến principal trong trang HTML bằng cách sử dụng thuộc tính 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. Kết luận

Bài viết này đã chỉ ra cách lấy thông tin người dùng trong ứng dụng Spring, bắt đầu với cơ chế truy cập tĩnh phổ biến trong bean, sau đó là một số cách tốt hơn để lấy thông tin người dùng.