starter-kit/docs/AUTHENTICATION.md
ulflow_phattt2901 9df4673657
Some checks failed
CI Pipeline / Security Scan (push) Failing after 4m42s
CI Pipeline / Lint (push) Failing after 5m1s
CI Pipeline / Test (push) Has been skipped
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Notification (push) Successful in 2s
chore: Update config file
2025-05-25 15:22:23 +07:00

5.6 KiB

Hệ thống Xác thực và Phân quyền

Mục lục

  1. Tổng quan
  2. Luồng xử lý
  3. Các thành phần chính
  4. Bảo mật
  5. 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

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ý:
    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
// 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
auth:
  access_token_expiry: 15m
  refresh_token_expiry: 7d
  jwt_secret: your-secret-key
  refresh_secret: your-refresh-secret
  1. 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)