Quay lại
Featured image of post JWT là gì? Tất tần tật về JWT

JWT là gì? Tất tần tật về JWT

Nó là viết tắt của `JSON Web Token`, JWT là 1 chuỗi JSON được mã hóa, JWT là phương thức để giao tiếp giữa Back-End và Front-End

✅ JWT là gì vậy nhỉ?

  • Nó là viết tắt của JSON Web Token
  • JWT là 1 chuỗi JSON được mã hóa, nó trông thế này đây:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • Các bạn copy chuỗi trên, xong vào đây dán vào xem thử nó thế nào nhé 🙂
  • JWT là phương thức để giao tiếp giữa Back-End và Front-End (Stateless). Nghĩa là Back-End chỉ tạo ra 1 chuỗi token cho user khi đăng nhập, và trả chuỗi này về Front-End, Back-End hoàn toàn không lưu trữ token này trên server.
  • Cơ chế hoạt động giống như hình dưới đây:

✅ Tại sao JWT lại sinh ra?

  • Trước đây chúng ta lập trình web, lúc đó điện thoại di động chưa phổ biến, nên không có app cho điện thoại di động, vì thế chỉ sử dụng cơ chế xác thực người dùng bằng Session Based.
  • Session Based là gì?
    • Các bạn xem hình dưới đây:

    • Các bạn thấy nó cũng tương tự với JWT, nhưng khác nhau chỗ không xài JWT mà xài cookie phải không?

    • Đúng vậy nó sẽ dùng cookie để định danh người dùng, và sessionId sẽ được lưu trữ trên phía server, ở dạng text.

    • Để biết người dùng đã đăng nhập hay chưa, và id của user là gì…

  • Sau khi có website chạy với session based rồi, giờ đột nhiên có nhu cầu thêm 1 app cho điện thoại nữa, vậy phải làm thế nào?
  • App trên điện thoại đâu có cookie để xài sessionId như web được???
  • Cuối cùng, 1 cơ chế mới được định nghĩa ra để giải quyết vấn đề này, đó là dùng Json Web Token. Nó mang chữ web thôi, nhưng xài ở đâu cũng được.

✅ Trong chuỗi JWT có những gì vậy?

JWT có 3 phần: Header, Payload và Signature, chi tiết các bạn có thể xem hình dưới:

  • Header, trong header sẽ có 2 thuộc tính:

    • alg: thuật toán mã hoá của JWT, thường sẽ là HS256
    • typ: loại token, thường sẽ là JWT
  • Payload: là nơi chứa các data cần thiết để định danh user, ví dụ user id, email, và các thông tin khác thường dùng như sau:

    JWT Payload keys

  • Signature: là chữ ký điện tử của JWT, dùng để verify JWT này có được tạo ra đúng không, dựa trên thuật toán mã hoá như sau:

    1. base64UrlEncode(header)
    2. base64UrlEncode(payload)
    3. HMACSHA256(#1, #2, secretKey)
    • secretKey là chuỗi ngẫu nhiên được lưu trữ trên server
    • secretKey dùng để tạo ra Signature cho JWT và verify JWT có hợp lệ hay không.
    var signature = HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret
    );
    
    var jwt = base64UrlEncode(header) + "." +  base64UrlEncode(payload) + "." + signature;
    

✅ JWT hoạt động thế nào vậy?

  • Cơ chế JWT khá đơn giản:
    • Server sau khi xác thực đúng user thì trả về 1 chuỗi mã hoá cho client
    • Client lưu lại mã này ở local, có thể lưu ở cookie, localStorate, AsyncStorage, SharedPreferences... hay bất cứ đâu bạn muốn mà có thể truy cập nhanh để lấy giá trị là được.
    • Mỗi request sau lên server thì set JWT vào header trước khi gửi lên.
    • Server lấy JWT từ header, verify coi thử JWT có hợp lệ không, hợp lệ thì cho vào, không thì đá lỗi 401 về cho client.
  • Các bạn có thể tham khảo ở hình dưới sẽ chi tiết hơn:

✅ Làm thế nào để verify JWT có hợp lệ không nhỉ?

  • Để verify 1 chuỗi JWT có hợp lệ hay không thì nó sẽ thế này:
    • Đầu tiên, server sẽ giải mã (decode) chuỗi JWT của header và payload ra, trong payload sẽ có các thông tin như:

      • iss: Người tạo là ai
      • nbf: Not before, token này có tới thòi điểm hợp lệ chưa
      • exp: Expiration time, token này có hết hạn chưa
    • Server kiểm tra các thông tin trên, nếu bất cứ thông tin nào không hợp lệ, thì sẽ trả lỗi ra.

    • Tiếp theo server sẽ thử hash header và payload với thuật toán tạo JWT trên để so sánh với Signature có giống không, nếu không giống thì cũng trả ra lỗi.

      var signature = HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        secret
      );
      
    • Các bạn thử tạo theo thuật toán này xem có ra được chuỗi JWT không nhé 😉

✅ Thử tạo 1 chuỗi JWT bằng NodeJS như thế nào?

  • Bây giờ chúng ta thử dùng NodeJS tạo ra 1 chuỗi JWT thử xem nhé.
    • Bạn tạo 1 file create-jwt.js

    • Tiếp tục bạn chạy lệnh: npm init, xong làm theo hướng dẫn trên terminal:

      package name: (demo-jwt) 
      version: (1.0.0) 
      description: 
      entry point: (index.js) 
      test command: 
      git repository: 
      keywords: 
      author: 
      license: (ISC) 
      About to write to /home/username/demo-jwt/package.json:
      
      {
        "name": "demo-jwt",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1"
        },
        "author": "",
        "license": "ISC"
      }
      
      Is this OK? (yes)
      
    • Giờ bạn chạy tiếp lệnh này: npm install jsonwebtoken

    • Xong tạo file create-jwt.js với nội dung sau:

      var jwt = require('jsonwebtoken');
      
      var token = jwt.sign({
        sub: 'e271a680-3e55-45bd-bbcf-aa4576ac835f',
        iss: 'JWT Demo',
        iat: Math.floor(Date.now() / 1000) - 30,
        data: {
          test: 'abc'
        }
      }, 'secretKey@123', { expiresIn: '1m' });
      
      console.log('token', token);
      
    • Vậy là xong phần tạo JWT với nodejs rồi, giờ chạy thử: node create-jwt.js

    • Bạn sẽ thấy kết quả như sau:

      token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
            eyJzdWIiOiJlMjcxYTY4MC0zZTU1LTQ1YmQtYmJjZi1hYTQ1NzZhYzgzNWYiLCJpc3MiOiJKV1QgRGVtbyIsImRhdGEiOnsidGVzdCI6ImFiYyJ9fQ.
            3ibxGqZi7n-3MjwbuKAYBkFYVwf59qUZt6Q6nbgp_wI
      
    • Bạn thử copy quăng vô jwt.io xem thử được thông tin gì nhé 😎

✅ Thử verify chuỗi JWT với nodejs nào.

  • Sau khi tạo xong JWT thì mình verify chuỗi xem hợp lệ hay không nhé.
    • Tạo file verify-jwt.js với nội dung sau:

      var token = '...'; // Thay token ở trên vào chỗ dấu ... hen.
      
      try {
        var decoded = jwt.verify(token, 'secretKey@123);
        console.log('token data', decoded);
      } catch(err) {
        console.log('Không thể verify token này')
      }
      
    • Bạn chạy thử node verify-jwt.js xem kết quả thế nào nhé 😇

✅ Thử hack JWT có được không?

  • Bây giờ mình có tình huống thế này:
    1. Bạn tạo 1 JWT ở trên
    2. Copy dán vào jwt.io
    3. Copy phần Signature để giữ lại đâu đó, có thể dán vào IDE để giữ lại tí mình có việc dùng lại nhé 😂
    4. Sửa lại payload phần sub thành 1 id của admin
    5. jwt.io tự tạo lại 1 chuỗi JWT mới, Signature hoàn toàn khác.
    6. Copy chuỗi mới, dán vào file verify-jwt.js và chạy thử.
  • Tình huống khác, tiếp theo tình huống trên nhé:
    1. Copy Signature lúc nãy giữ lại.
    2. Dán vào phần `

✅ Ưu, nhược điểm của JWT là gì?

(Đang cập nhật)

✅ Làm sao để logout 1 user đang xài JWT hợp lệ trước thời hạn?

  • Khi sử dụng Session based thì sessionId được lưu trên server, khi user logout thì chúng ta chỉ việc xóa sessionId trên server là xong.
  • Nhưng đang dùng JWT, server không lưu lại, thì làm sao để logout user nhỉ?
    • Không có cách nào logout 1 user khi họ đang sử dụng JWT, nghĩa là cho dù user đã nhấn nút logout rồi, nhưng lấy JWT đó vẫn request lên server bình thường nhé, server không hề biết được user đã logout rồi.
    • Vậy cách nào để từ chối các request sau khi user đã logout? Chúng ta có 1 cách là:
      • Khi user logout, gửi token lên server với request logout.
      • Server lưu lại JWT đã logout trên Redis hoặc 1 nơi nào đó.
      • Bất cứ request nào lên server thì server kiểm tra JWT có trên chỗ lưu JWT đã logout hay không, nếu có thì từ chối request, đá lỗi 401 Unauthorized về cho client.

🐗 Vậy là xong toàn bộ kiến thức về JWT, bạn có thể làm thử tất cả ví dụ trên nhé, để nắm kiến thức kỹ hơn.

❔ Nếu các bạn có thắc mắc gì, bất cứ gì chưa rõ, cứ comment để mình giải thích kỹ hơn nhé🙂

Cảm ơn các bạn đã theo dõi bài viết.

Bình luận sử dụng Facebook hoặc Google bên dưới nhé :)