Chuyển tới nội dung chính

API và Xác thực

1. API​

2. Token & Auth​

2.1. Tổng quan các thành phần​

Hệ thống FE và API Gateway bao gồm các thành phần sau:

React App​

  • Chỉ xử lý giao diện và logic nghiệp vụ trên giao diện FE.
  • Chỉ giao tiếp với Kong API Gateway.
  • Không gọi trực tiếp vào Auth Service hoặc Core Service.
  • Lưu access_token và refresh_token trong localStorage.
  • Khi gọi API, lấy access_token từ localStorage và gắn vào header Authorization.
  • Khi token hết hạn, dùng refresh_token để gọi API refresh token.
  • Khi logout, xóa token khỏi localStorage.

Kong API Gateway​

Kong là cổng vào duy nhất của hệ thống.

Kong chịu trách nhiệm:

Route request đến đúng service
Kiểm tra CORS
Giới hạn request bằng Rate Limit
Kiểm tra token
Forward request hợp lệ vào service phía sau
Trả response về client
Ghi log request

Frontend chỉ gọi vào Kong, không gọi trực tiếp vào Auth Service hoặc Core Service.


Auth Service​

Auth Service xử lý các nghiệp vụ liên quan đến xác thực:

Login
Refresh token
Logout
Mapping user nếu cần
Custom logic trước hoặc sau khi gọi Keycloak

Auth Service không tự cấp token, mà làm việc với Keycloak để xác thực và nhận token.


Keycloak​

Keycloak là hệ thống quản lý danh tính.

Keycloak chịu trách nhiệm:

Quản lý user
Quản lý role
Quản lý realm
Quản lý client
Xác thực username/password
Cấp access_token
Cấp refresh_token
Validate token
Revoke token

Core Service​

Core Service xử lý nghiệp vụ chính của hệ thống.

Ví dụ:

Quản lý người dùng
Quản lý danh mục
Quản lý đơn hàng
Báo cáo
Xử lý dữ liệu nghiệp vụ

Core Service chỉ nên nhận request đã đi qua Kong và đã được kiểm tra token hợp lệ.

2.2. Luồng sử dụng token​

Dưới đây là chia ra theo từng phần, dễ đưa vào tài liệu hơn.


2.2.1. Tổng quan luồng xác thực​

Hệ thống sử dụng mô hình xác thực bằng access_token và refresh_token.

Trong đó:

access_token → dùng để gọi API nghiệp vụ
refresh_token → dùng để xin access_token mới khi token hết hạn

Token được lưu ở phía trình duyệt bằng localStorage.

Tất cả request từ frontend không gọi trực tiếp vào service phía sau, mà đi qua:

React App
→ Kong API Gateway
→ Auth Service / Core Service
→ Keycloak

2.2.2. Luồng đăng nhập​

React App
→ Kong Gateway
(Verify Request: CORS, Rate Limit, Kong Auth)
→ Auth Service
→ Keycloak
→ Trả access_token + refresh_token
→ React lưu token vào localStorage

Khi người dùng đăng nhập, React App gửi request đến API login:

POST /auth-service/oauth2/login

Request này đi qua Kong API Gateway. Trước khi chuyển tiếp request, Kong sẽ xử lý các bước như CORS, Rate Limit rồi mới route request đến Auth Service.

Auth Service nhận username và password, sau đó gửi sang Keycloak để xác thực.

Nếu thông tin đăng nhập hợp lệ, Keycloak trả về:

access_token
refresh_token

Sau đó token được trả về frontend thông qua Kong.

Frontend lưu token vào localStorage:

localStorage.setItem("access_token", accessToken)
localStorage.setItem("refresh_token", refreshToken)

2.2.3. Luồng gọi API nghiệp vụ​

React App
→ Lấy access_token từ localStorage
→ Gắn Authorization Header
→ Kong Gateway (Verify Request: CORS, Rate Limit, Kong Auth)
→ Core Service
→ Trả JSON về React App

Khi người dùng gọi API nghiệp vụ, ví dụ:

GET /core-service/api/v1/BHAPI

Frontend sẽ lấy access_token từ localStorage:

const token = localStorage.getItem("access_token")

Sau đó gắn token vào request header:

Authorization: Bearer access_token

Request được gửi đến Kong. Kong kiểm tra CORS, Rate Limit và Token Check.

Nếu token hợp lệ, Kong mới forward request đến Core Service.

Core Service xử lý nghiệp vụ và trả dữ liệu JSON về frontend.


2.2.4. CORS và Rate Limit​

CORS

CORS dùng để kiểm soát frontend domain nào được phép gọi API.

Ví dụ frontend chạy ở:

https://app.example.com

API chạy ở:

https://api.example.com

Do khác domain, trình duyệt sẽ kiểm tra CORS.

Với request có header đặc biệt như:

Authorization: Bearer token

trình duyệt thường gửi request OPTIONS trước. Đây gọi là CORS Preflight.

Kong cần trả về các header cho phép:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type

Nếu CORS không hợp lệ, request sẽ bị trình duyệt chặn trước khi vào service.

Rate Limit

Rate Limit dùng để giới hạn số lượng request trong một khoảng thời gian.

Mục đích là bảo vệ hệ thống khỏi:

spam request
brute-force login
gọi API quá nhiều
tấn công vào endpoint nhạy cảm

Ví dụ có thể cấu hình:

/auth-service/oauth2/login → giới hạn thấp hơn
/auth-service/oauth2/refresh → giới hạn vừa phải
/core-service/api/v1/* → giới hạn theo user hoặc token

Nếu request vượt quá giới hạn, Kong trả về:

429 Too Many Requests

2.2.6. Token Check​

Token Check dùng để kiểm tra request có token hợp lệ hay không.

Frontend gửi token qua header:

Authorization: Bearer access_token

Kong kiểm tra token bằng một trong hai cách:

Verify JWT trực tiếp
hoặc
Introspection qua Keycloak

Nếu token hợp lệ:

Kong → forward request sang Core Service

Nếu token sai, hết hạn hoặc bị revoke:

401 Unauthorized

2.2.7. Luồng refresh token​

API trả 401 Unauthorized
→ React lấy refresh_token từ localStorage
→ Gọi /auth-service/oauth2/refresh
→ Kong
→ Auth Service
→ Keycloak
→ Trả token mới
→ React cập nhật localStorage
→ Gọi lại API ban đầu

Khi access_token hết hạn, frontend sẽ nhận lỗi:

401 Unauthorized

Khi đó frontend lấy refresh_token từ localStorage:

const refreshToken = localStorage.getItem("refresh_token")

Sau đó gọi API refresh:

POST /auth-service/oauth2/refresh

Auth Service gửi refresh_token sang Keycloak để xin token mới.

Nếu refresh token còn hợp lệ, Keycloak trả về:

new_access_token
new_refresh_token

Frontend cập nhật lại token mới vào localStorage:

localStorage.setItem("access_token", newAccessToken)
localStorage.setItem("refresh_token", newRefreshToken)

Sau đó frontend có thể gọi lại API nghiệp vụ ban đầu.


2.2.8. Luồng logout​

React App
→ Lấy refresh_token từ localStorage
→ Gọi /auth-service/oauth2/logout
→ Kong
→ Auth Service
→ Keycloak revoke token
→ React xóa token khỏi localStorage

Khi người dùng đăng xuất, frontend lấy refresh_token từ localStorage và gọi:

POST /auth-service/oauth2/logout

Auth Service gửi yêu cầu revoke token sang Keycloak.

Sau khi logout thành công, frontend xóa token khỏi localStorage:

localStorage.removeItem("access_token")
localStorage.removeItem("refresh_token")

Hoặc có thể xóa toàn bộ:

localStorage.clear()

2.3. Lưu ý khi dùng localStorage​

localStorage dễ triển khai vì frontend có thể chủ động lưu, đọc và gắn token vào request.

Tuy nhiên, token trong localStorage có thể bị JavaScript đọc được. Vì vậy cần chú ý bảo vệ frontend khỏi lỗi XSS.

Một số lưu ý:

Không render HTML không an toàn
Không dùng dangerouslySetInnerHTML nếu không cần
Validate dữ liệu đầu vào
Escape dữ liệu khi hiển thị
Cấu hình CSP nếu có thể
Không lưu thông tin nhạy cảm khác trong localStorage