Tổng quan Spring Security, một số khái niệm cơ bản
spring boot
80
spring security
62
JWT
12
White

Banh Mii viết ngày 28/05/2021

Spring security là 1 framework thuộc hệ thống Spring, dành riêng cho việc thiết lập bảo mật của ứng dụng bao gồm authentication và authorization. Mặc dù hiện nay có rất nhiều bài hướng dẫn xây dựng một application sử dụng spring-security step by step, nhưng vẫn còn một số khái niệm dễ gây nhầm lẫn, nhất là với những bạn bắt đầu làm quen nên mình muốn tổng hợp lại trong bài viết này.
Bài viết có tham khảo từ trang https://www.toptal.com/spring/spring-security-tutorial.

1. Thuật ngữ

Ở phần này, mình sẽ làm rõ một vài thuật ngữ dễ gây nhầm lẫn:

Authentication vs Authorization

  • Authentication: quá trình xác minh user, dựa vào thông tin đăng nhập mà user cung cấp. Ví dụ khi login, bạn nhập username và password, nó giúp hệ thống nhận ra bạn là ai.
  • Authorization: Quá tình xác định xem user có quyền thực hiện những chức năng nào của hệ thống (đọc/sửa/xóa data), sau khi user đã authenticated thành công.

Hiểu nôm na thì authentication là cái công thứ nhất, xem user có thuộc hệ thống hay không, authorization là cái cổng thứ hai, xem user được phép làm những gì trong hệ thống đó.

Principle, Granted authority, Role

Khi xây dựng ứng dụng sử dụng spring security, bạn sẽ dễ dàng bắt gặp những thuật ngữ này, đừng nhầm lẫn nhé.

  • Principle: chỉ authenticated user hiện tại (user đã đăng nhập thành công và thực hiện action hiện tại)
  • Granted authority: quyền được thực hiện action của authenticated user.
  • Role: một NHÓM QUYỀN của authenticated user.

Encoding, Encrypt và Hashing

  • Encoding: quá trình convert data từ dạng này sang dạng khác, không sử dụng mã hóa. Trong nhiều trường hợp, encoding dùng để giảm size của data (video và audio file). Một số kiểu encoding thường dùng: ASCII, BASE64, UNICODE
  • Encrypt: quá trình transform data mà các data này cần được bảo vệ. Có 2 kiểu encrypt là symetric (đối xứng) và asymetric (bất đối xứng). Về cơ bản thì mã hóa đối xứng là sử dụng 1 key (gọi là secret key) để encrypt data và decrypt data, một số thuật toán mã hóa đối xứng thường gặp là AES-128, AES-192, AES-256. Trong khi đó, mã hóa bất đối xứng sử dụng hai keys: public key và private key, public key để encrypt data và private key để decrypt data, một số kiểu mã hóa bất đối xứng thường gặp là RSA (phổ biến nhất), DSA.
  • Hashing: quá trình convert data thành một chuỗi hash sử dụng hash function. Một số giải thuật hash thường gặp: MD5, SHA256. Data hashed không thể được chuyển đối theo hướng ngược lại (theo lý thuyết). Do vậy, một trong những ứng dụng quan trọng của hashing là lưu password.

2. Tạo ứng dụng spring security đầu tiên

Trước khi tìm hiểu về kiến trúc, hãy cùng mình tạo ứng dụng sử dụng spring security cơ bản nhất nhé.
Mình sử dụng https://start.spring.io/ để tạo ra project spring boot, ở trong phạm vi bài này, chỉ cần Spring web dependency là đủ:

    <dependencies>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
    </dependencies>

Khi đã có project, mình tạo một REST Controller đơn giản như sau:

@RestController @RequestMapping("hello")
public class HelloRestController {

@GetMapping("user")
public String helloUser() {
    return "Hello User";
}

@GetMapping("admin")
public String helloAdmin() {
    return "Hello Admin";
}

}

Sau đó, mình build và run project, rồi truy cập địa chỉ:

http://localhost:8080/hello/user sẽ trả về chuỗi "Hello User".
http://localhost:8080/hello/admin sẽ trả về chuỗi "Hello Admin".

Bây giờ, mình add thêm Spring security dependency vào file pom.xml:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
     </dependency>

Sau đó, build và run lại ứng dụng rồi truy cập vào địa chỉ như bên trên. Lúc này, hệ thống sẽ tự động redirect sang http://localhost:8080/login.
Thông thường, việc thêm các dependency vào file pom sẽ chưa có hiệu quả cho đến khi chúng ta thực hiện các config hay sử dụng đoạn code của thư viện, nhưng với Spring Security thì khác, như bạn có thể thấy, nó tự động apply ngay sau khi chúng ta thêm dependency vào file pom.xml mà không cần làm gì cả.
Để đăng nhập, bạn điền username là "user", còn password sẽ được generate trong quá trình run ứng dụng:
alt text

Password này thay đổi sau mỗi lần re-run ứng dụng.
Nếu bạn muốn sử dụng một password cố định, và username khác, bạn có thể thêm property trong file config application.properties:

spring.security.user.name=admin
spring.security.user.password=123456

Mặc định, Spring security sử dụng session-based authentication như bên trên, có nghĩa là server tạo một session cho người dùng, sessionID được lưu trên cookie ở client, sau khi user đăng nhập, cookie sẽ được gửi cùng với các request tiếp theo, server so sánh sessionID để xác minh thông tin của người dùng.
Tuy nhiên, cơ chế này hiện nay không được khuyến khích do một số nhược điểm như khó scale ngang, chiếm nhiều bộ nhớ (vì sessionID cần được lưu trữ ở server), mà thay vào đó, JWT-based stateless authentication ngày càng chiếm ưu thế và được sử dụng phổ biến hơn.

Nhân đây thì cùng giới thiệu luôn về JWT (Json Web Token):

JWT (Json Web Token)

Là một chuỗi các giá trị được mã hóa dưới dạng Base64url, gồm 3 phần chính là Header, Payload và Signature.

  • Header: chứa hai thông tinh chính, loại token (chính là JWT) và giải thuật được sử dụng, thường là SHA256 hay RSA.
  • Payload: chứa các thông tin chính về user (hoặc bất kỳ thông tin nào mà bạn cho là cần thiết) và các thông tin khác như expiration time.
  • Signature: để tạo ra signature, cần có encoded header, encoded payload, secret key và giải thuật đã được nêu trong phần Header.
    Ví dụ nếu bạn muốn tạo 1 signature, dùng giải thuật HMACSHA256:

    HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        secret)
    

Signature nhằm đảm bảo messgae không bị thay đổi trong quá trình truyền và cũng dành để xác minh người gửi.
Sau đây là một ví dụ về JWT:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.
yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw

Mỗi dấu chấm đánh dấu 1 phần của JWT.

3. Tổng quan kiến trúc của Spring security

alt text

Spring security filters chain

Filter là một thành phần của Spring security, nơi nhận request, xử lý request và giao lại cho filter tiếp theo trong chuỗi. Mỗi filter có một nhiệm vụ cụ thể tùy thuộc vào nhu cầu. Một số filter thường thấy: authentication filter, CORS filter, CSRF filter...
Nếu muốn tạo custom filter trong Spring security, class filter đó phải implement Fiter interface và override doFilter() method.

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    // do something
    chain.doFilter(request, response);
}
  • ServletRequest request: là HTTP request bao gồm những thông tin mà client gửi đến

  • ServletResponse: HTTP response. Spring security sử dụng ServletResponse để chỉnh sửa response trước khi gửi lại cho client hoặc gửi cho các filter tiếp theo trong chuỗi.

  • FilterChain chain: để forward request đến filter tiếp theo trong chuỗi.

Authentication Provider

AuthenticationProvider có trách nhiệm thực hiện các authentication cụ thể. Interface của nó gồm 2 method:

  • authenticate(Authentication authentication): thực hiện authentication với request.
  • support(Class<?> authenticationType): check nếu provider hiện tại hỗ trợ kiểu authentication truyền vào.

Authentication manager

Đóng vai trò như một điều phối viên để ta có thể đăng ký nhiều providers, và tùy thuộc vào kiểu requuest, nó sẽ phần phối authentication request vào đúng provider.

UserDetailService

UserDetailService được mô tả như một core interface, nơi lấy thông tin user bằng method:

  • UserDetails loadUserByUsername(String username): trong hầu hết các trường hợp, thông tin này được lấy từ database, dựa vào userName.

Trên đây là một số thông tin cơ bản trước khi các bạn muốn tìm hiểu sâu hơn về Spring security. Nếu có ý kiến gì bạn hãy comment phía dưới nhé.
Cảm ơn các bạn đã đọc bài ^^.

BanhMii 28-05-2021

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Banh Mii

4 bài viết.
17 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
3 0
Hiện nay, phần lớn các project đều dùng Git để quản lý, với các thao tác thông thường như pull, push, merge thì có lẽ đã quá quen thuộc với các bạn...
Banh Mii viết 4 tháng trước
3 0
White
2 0
Ở phần trước, chúng ta đã tìm hiểu cấu trúc bên trong và cách khởi tạo HashMap, ở phần này mình tiếp tục đi sâu hơn về cách HashMap hoạt động nhé. ...
Banh Mii viết 5 tháng trước
2 0
White
2 0
HashMap được coi là một trong những Java Collection phổ biến nhất, và cũng thường xuyên góp mặt trong list các câu hỏi phỏng vấn. Vậy bạn đã bao g...
Banh Mii viết 5 tháng trước
2 0
Bài viết liên quan
White
4 0
I used Spring boot, Hibernate few times back then at University, I'v started using it again recently. In this (Link), I want to check how Spring J...
Rey viết hơn 2 năm trước
4 0
White
0 0
Giới thiệu Trong bài hôm nay chúng ta sẽ tìm hiểu cách handle request POST của Spring Boot. Trước đó, bạn nên biết 1. 「Spring Boot 8」Tạo Web He...
https://loda.me viết hơn 2 năm trước
0 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
4 bài viết.
17 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!