[Bài đọc] Spring Security

14. Bảo mật

Spring Security là một dự án nổi bật trong hệ sinh thái Spring. Spring Security cung cấp các dịch vụ bảo mật toàn diện cho các ứng dụng doanh nghiệp có nền tảng Java EE.

Spring Security cung cấp 2 cơ chế cơ bản:

  • Authentication (xác thực): là tiến trình thiết lập một principal. Principal có thể hiểu là một người, hoặc một thiết bị, hoặc một hệ thống nào đó có thể thực hiện một hành động trong ứng dụng của bạn.
  • Authorization (phân quyền) hay Access-control: là tiến trình quyết định xem một principal có được phép thực hiện một hành động trong ứng dụng của bạn hay không. Trước khi diễn tiến tới Authorization, principal cần phải được thiết lập bởi Authentication.

Ta có thể thấy đây là 2 cơ chế khá phổ biến trong các dịch vụ bảo mật, không chỉ riêng Spring Security.

Các thành phần cốt lõi

Security, SecurityContext và Authentication

SecurityContext là interface cốt lõi của Spring Security, lưu trữ tất cả các chi tiết liên quan đến bảo mật trong ứng dụng. Khi chúng ta kích hoạt Spring Security trong ứng dụng thì SecurityContext cũng sẽ được kích hoạt theo.

Chúng ta sẽ không truy cập trực tiếp vào SecurityContext, thay vào đó sẽ sử dụng lớp SecurityContextHolder. Lớp này lưu trữ security context hiện tại của ứng dụng, bao gồm chi tiết của principal đang tương tác với ứng dụng. Spring Security sẽ dùng một đối tượng Authentication để biểu diễn thông tin này. Đoạn code dưới đây sẽ giúp chúng ta lấy được username của principal đã được xác thực (username ở đây ta nên hiểu là username trong cặp username – password mà người dùng nhập vào khi đăng nhập):

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (principal instanceof UserDetails) {
    String username = ((UserDetails) principal).getUsername();
} else {
    String username = principal.toString();
}

Đoạn code này có thể đặt ở bất kỳ đâu trong ứng dụng.

UserDetails và UserDetailsService

Trong đoạn code trên, chúng ta có được một principal từ đối tượng Authentication. Principal đơn giản chỉ là một đối tượng và sẽ được ép kiểu sang UserDetails.

UserDetails là một interface cốt lõi của Spring Security. Nó đại diện cho một principal nhưng theo một cách mở rộng và cụ thể hơn. Vậy UserDetails cung cấp cho ta những thông tin gì? UserDetails bao gồm các method sau:

  • getAuthorities(): trả về danh sách các quyền của người dùng
  • getPassword(): trả về password đã dùng trong qúa trình xác thực
  • getUsername(): trả về username đã dùng trong qúa trình xác thực
  • isAccountNonExpired(): trả về true nếu tài khoản của người dùng chưa hết hạn
  • isAccountNonLocked(): trả về true nếu người dùng chưa bị khóa
  • isCredentialsNonExpired(): trả về true nếu chứng thực (mật khẩu) của người dùng chưa hết hạn
  • isEnabled(): trả về true nếu người dùng đã được kích hoạt

Chúng ta có thể thấy UserDetails mới chỉ cung cấp các phương thức để truy cập các thông tin cơ bản của người dùng. Để mở rộng thêm các thông tin, chúng ta sẽ tạo một lớp CustomUserDetails implements org.springframework.security.userdetails.UserDetails (tên lớp là tùy ý, bạn đặt tên thế nào cũng được).

Câu hỏi tiếp theo đặt ra là ta sẽ tạo implementation của UserDetails ở đâu trong ứng dụng? Câu trả lời là ta sẽ dùng UserDetailsService. UserDetailsService là một interface có duy nhất một phương thức:

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

Tham số truyền vào chỉ gồm có username của người dùng. Ta sẽ tìm kiếm trong CSDL, record thỏa mãn username. Nếu không tìm thấy, ta sẽ ném ra ngoại lệ UsernameNotFoundException.

Phương thức loadUserByUsername() sẽ trả về một implementation của UserDetails. Implementation ở đây có thể là:

  • org.springframework.security.core.userdetails.User
  • CustomUserDetails implements org.springframework.security.userdetails.UserDetails mà mình đã nói ở trên

Nhiệm vụ của chúng ta là cần phải tạo một lớp UserDetailsServiceImpl implements UserDetailsService.

GrantedAuthority

Ở phần trên, mình đã đề cập đến phương thức getAuthorities(). Phưong thức này sẽ trả về một tập hợp các đối tượng GrantedAuthority. Một GrantedAuthority là một quyền được ban cho principal. Các quyền đều có tiền tố là ROLE_, ví dụ như ROLE_ADMINROLE_MEMBER …

Leave a Reply

Your email address will not be published. Required fields are marked *