# Hệ thống Xác thực và Phân quyền ## Mục lục 1. [Tổng quan](#tổng-quan) 2. [Luồng xử lý](#luồng-xử-lý) - [Đăng nhập](#đăng-nhập) - [Làm mới token](#làm-mới-token) - [Đăng xuất](#đăng-xuất) 3. [Các thành phần chính](#các-thành-phần-chính) - [Auth Middleware](#auth-middleware) - [Token Service](#token-service) - [Session Management](#session-management) 4. [Bảo mật](#bảo-mật) 5. [Tích hợp](#tích-hợp) ## 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 ```mermaid 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 ```mermaid 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 ```mermaid 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ý**: 1. Lấy token từ header 2. Xác thực token 3. Kiểm tra session trong store 4. 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ý**: 1. Lấy thông tin user từ context 2. Kiểm tra user có vai trò phù hợp không 3. 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 1. **Token Storage** - Access Token: Lưu trong memory (không lưu localStorage) - Refresh Token: HttpOnly, Secure, SameSite=Strict cookie 2. **Token Rotation** - Mỗi lần refresh sẽ tạo cặp token mới - Vô hiệu hóa refresh token cũ 3. **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 1. **Xử lý token** ```javascript // 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 1. **Cấu hình** ```yaml auth: access_token_expiry: 15m refresh_token_expiry: 7d jwt_secret: your-secret-key refresh_secret: your-refresh-secret ``` 2. **Sử dụng middleware** ```go // Á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) ```