Giả định hệ thống sử dụng JWT làm access token. Vậy làm thế nào để user có thể revoke token/session
Khi mới học backend khi làm việc với JWT đa số thường sẽ chỉ lấy userId (và một số thông tin hỗ trợ authorize) đưa vào payload. Từ đó các bạn sẽ làm một middleware verified và lấy lại phần payload này. Đây là cách đơn giản nhất để làm quen với JWT cho login và authorize.
Lý do và giải pháp JWT
Tuy nhiên, khi cần quản lý lại session của user thì phải cần thêm ít nhất một table nữa (VD: user_sessions). Có table này thì middleware (hoặc identity service) sau khi verify và lấy được payload rồi phải đi check xem record tương ứng còn hay không. Từ đó chương trình có thể quyết định xử lý request hoặc dừng lại.
ID (pk) của bảng user_sessions có thể dùng cho “tid – Token identifier” trong payload của JWT token. Từ đó verify và parse ra là có id để query tìm kiếm.
Đương nhiên về hiệu năng sẽ tăng latency rất đáng kể vì tương ứng với mỗi request đều có một query đi vào table user_sessions. Vì thế chỗ này thường sẽ triển khai thêm caching để hỗ trợ tăng tốc truy vấn. Cache này đương nhiên cũng bị invalid ngay khi user revoke hoặc hết hạn TTL (tính theo thời gian hiệu lực còn lại của token JWT).
Table session này cũng bị nhiều record theo thời gian. Vì thế cũng cần một cron/scheduler đi xoá những record đã hết hạn – với field expired_at để làm điều kiện.
Các case study khác
Một số nghiệp vụ có thể làm được với bảng user_sessions
:
- Có thể giới hạn số lượng session đồng thời của 1 user.
- Có thể lưu thêm một số metadata cần thiết như: IP, Device Name, Browser Name, GEO Location…
- Hệ thống có thể cưỡng chế logout tất cả sessions của một user bất kỳ, hoặc khi user thực hiện đổi password.
- Hệ thống có thể detect trường hợp access token của user bị lấy cắp và sử dụng ở một device khác.
- Hệ thống có thể detect “vị trí hoặc thiết bị khác thuờng” dựa trên lịch sử đăng nhập.
- Và đương nhiên phía user vẫn có thể listing và revoke bất kì một session nào của họ nếu cần.
Đây là minh họa:
sequenceDiagram autonumber participant User participant Frontend participant Backend participant Database participant JWT User->>Frontend: Enter login credentials Frontend->>Backend: Send credentials Backend->>Database: Validate credentials Database-->>Backend: Return user data if valid Backend->>JWT: Generate JWT JWT-->>Backend: Return JWT Backend->>Database: Store session in session table Backend-->>Frontend: Return JWT Frontend-->>User: Store JWT User->>Frontend: Make a request Frontend->>Backend: Send request with JWT Backend->>JWT: Validate JWT JWT-->>Backend: Return validation result Backend->>Database: Check session in session table Database-->>Backend: Return session status Backend-->>Frontend: Return requested data if valid User->>Frontend: Revoke session Frontend->>Backend: Send revoke request with JWT Backend->>Database: Delete session from session table Database-->>Backend: Confirmation of deletion Backend-->>Frontend: Inform User of revocation Note over User, Backend: User is logged out and session is revoked.
>>Xem thêm: CRUD là gì?