✅ 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:- Các thông tin các các bạn có thể tham khảo ở đây: https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields
-
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:base64UrlEncode(header)
base64UrlEncode(payload)
HMACSHA256(#1, #2, secretKey)
secretKey
là chuỗi ngẫu nhiên được lưu trữ trên serversecretKey
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ỗi401
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à ainbf
: Not before, token này có tới thòi điểm hợp lệ chưaexp
: 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:
- Bạn tạo 1 JWT ở trên
- Copy dán vào jwt.io
- 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é 😂 - Sửa lại payload phần
sub
thành 1 id của admin - jwt.io tự tạo lại 1 chuỗi JWT mới,
Signature
hoàn toàn khác. - 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é:
- Copy
Signature
lúc nãy giữ lại. - Dán vào phần `
- Copy
✅ Ư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óasessionId
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.