5.6 KiB
5.6 KiB
Hệ thống Xác thực và Phân quyền
Mục lục
Tổng quan
Hệ thống xác thực sử dụng JWT (JSON Web Tokens) với cơ chế refresh token để đảm bảo bảo mật. Mỗi phiên đăng nhập sẽ có:
- Access Token: Có thời hạn ngắn (15-30 phút)
- Refresh Token: Có thời hạn dài hơn (7-30 ngày)
- Session ID: Định danh duy nhất cho mỗi phiên
Luồng xử lý
Đăng nhập
sequenceDiagram
participant Client
participant AuthController
participant AuthService
participant TokenService
participant SessionStore
Client->>AuthController: POST /api/v1/auth/login
AuthController->>AuthService: Authenticate(credentials)
AuthService->>UserRepository: FindByEmail(email)
AuthService->>PasswordUtil: CompareHashAndPassword()
AuthService->>TokenService: GenerateTokens(userID, sessionID)
TokenService-->>AuthService: tokens
AuthService->>SessionStore: Create(session)
AuthService-->>AuthController: authResponse
AuthController-->>Client: {accessToken, refreshToken, user}
Làm mới Token
sequenceDiagram
participant Client
participant AuthController
participant TokenService
participant SessionStore
Client->>AuthController: POST /api/v1/auth/refresh
AuthController->>TokenService: RefreshToken(refreshToken)
TokenService->>SessionStore: Get(sessionID)
SessionStore-->>TokenService: session
TokenService->>TokenService: ValidateRefreshToken()
TokenService->>SessionStore: UpdateLastUsed()
TokenService-->>AuthController: newTokens
AuthController-->>Client: {accessToken, refreshToken}
Đăng xuất
sequenceDiagram
participant Client
participant AuthController
participant TokenService
participant SessionStore
Client->>AuthController: POST /api/v1/auth/logout
AuthController->>TokenService: ExtractTokenMetadata()
TokenService-->>AuthController: tokenClaims
AuthController->>SessionStore: Delete(sessionID)
AuthController-->>Client: 200 OK
Các thành phần chính
Auth Middleware
Authenticate()
- Mục đích: Xác thực access token trong header Authorization
- Luồng xử lý:
- Lấy token từ header
- Xác thực token
- Kiểm tra session trong store
- Lưu thông tin user vào context
RequireRole(roles ...string)
- Mục đích: Kiểm tra quyền truy cập dựa trên vai trò
- Luồng xử lý:
- Lấy thông tin user từ context
- Kiểm tra user có vai trò phù hợp không
- Trả về lỗi nếu không có quyền
Token Service
GenerateTokens(userID, sessionID)
- Tạo access token và refresh token
- Lưu thông tin session
- Trả về cặp token
ValidateToken(token)
- Xác thực chữ ký token
- Kiểm tra thời hạn
- Trả về claims nếu hợp lệ
Session Management
CreateSession(session)
- Tạo session mới
- Lưu vào Redis với TTL
- Trả về session ID
GetSession(sessionID)
- Lấy thông tin session từ Redis
- Cập nhật thời gian truy cập cuối
- Trả về session nếu tồn tại
Bảo mật
-
Token Storage
- Access Token: Lưu trong memory (không lưu localStorage)
- Refresh Token: HttpOnly, Secure, SameSite=Strict cookie
-
Token Rotation
- Mỗi lần refresh sẽ tạo cặp token mới
- Vô hiệu hóa refresh token cũ
-
Thu hồi token
- Đăng xuất sẽ xóa session
- Có thể thu hồi tất cả session của user
Tích hợp
Frontend
- Xử lý token
// Lưu token vào memory
let accessToken = null;
// Hàm gọi API với token
export const api = axios.create({
baseURL: '/api/v1',
headers: {
'Content-Type': 'application/json',
},
});
// Thêm interceptor để gắn token
api.interceptors.request.use(config => {
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
});
// Xử lý lỗi 401
export function setupResponseInterceptor(logout) {
api.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const { accessToken: newToken } = await refreshToken();
accessToken = newToken;
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return api(originalRequest);
} catch (error) {
logout();
return Promise.reject(error);
}
}
return Promise.reject(error);
}
);
}
Backend
- Cấu hình
auth:
access_token_expiry: 15m
refresh_token_expiry: 7d
jwt_secret: your-secret-key
refresh_secret: your-refresh-secret
- Sử dụng middleware
// Áp dụng auth middleware
router.Use(authMiddleware.Authenticate())
// Route yêu cầu đăng nhập
router.GET("/profile", userHandler.GetProfile)
// Route yêu cầu quyền admin
router.GET("/admin", authMiddleware.RequireRole("admin"), adminHandler.Dashboard)