Đăng nhập Admin
Mô tả Tổng quan
Tính năng Đăng nhập Admin cung cấp xác thực đặc biệt cho người dùng quản trị với quyền hạn cao hơn. Nó tuân theo luồng tương tự như đăng nhập user tiêu chuẩn nhưng bao gồm các kiểm tra bổ sung cho việc xác minh vai trò admin và tải user mở rộng. Tính năng này đảm bảo rằng chỉ những user có quyền admin phù hợp mới có thể truy cập các phần quản trị của ứng dụng, tạo ra sự phân tách rõ ràng giữa quyền truy cập user thông thường và khả năng quản trị.
Biểu đồ Hoạt động
---
config:
theme: base
layout: dagre
flowchart:
curve: linear
htmlLabels: true
themeVariables:
edgeLabelBackground: "transparent"
---
flowchart TD
%% Main components
AdminUser[Admin User]
FirebaseService[Firebase Authentication]
Database[(Database)]
%% Process steps with numbering
AdminUser --- Step1[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>1</span>
<p style='margin-top: 8px'>Gửi Đăng nhập</p>
</div>
]
Step1 --> ValidateRequest[Xác thực Yêu cầu]
ValidateRequest --- Step2[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>2</span>
<p style='margin-top: 8px'>Trích xuất Token</p>
</div>
]
Step2 --> ExtractToken[Trích xuất Firebase Token]
ExtractToken --- Step3[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>3</span>
<p style='margin-top: 8px'>Gửi đến Auth Service</p>
</div>
]
Step3 --> AuthService[Auth Service]
AuthService --- Step4[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>4</span>
<p style='margin-top: 8px'>Xác minh Token</p>
</div>
]
Step4 --> FirebaseService
FirebaseService --- Step5[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>5</span>
<p style='margin-top: 8px'>Kiểm tra Token</p>
</div>
]
Step5 --> TokenCheck{Token Hợp lệ?}
TokenCheck --- Step6A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step6A -->|Không| ReturnError[Trả về Lỗi]
TokenCheck --- Step6B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>6B</span>
<p style='margin-top: 8px'>Tìm User</p>
</div>
]
Step6B -->|Có| FindUser[Tìm User trong Database]
FindUser --- Step7[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>7</span>
<p style='margin-top: 8px'>Kiểm tra Sự tồn tại</p>
</div>
]
Step7 --> UserCheck{User Tồn tại?}
UserCheck --- Step8A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step8A -->|Không| ReturnError
UserCheck --- Step8B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>8B</span>
<p style='margin-top: 8px'>Kiểm tra Vai trò</p>
</div>
]
Step8B -->|Có| CheckRole[Kiểm tra Vai trò Admin]
CheckRole --- Step9[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>9</span>
<p style='margin-top: 8px'>Xác minh Quyền</p>
</div>
]
Step9 --> RoleCheck{Admin Role?}
RoleCheck --- Step10A[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #cc6666 !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step10A -->|Không| ReturnError
RoleCheck --- Step10B[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>10B</span>
<p style='margin-top: 8px'>Tải Dữ liệu</p>
</div>
]
Step10B -->|Có| LoadData[Tải Dữ liệu User & Nhóm]
LoadData --- Step11[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>11</span>
<p style='margin-top: 8px'>Tạo Cookie</p>
</div>
]
Step11 --> CreateCookie[Tạo Auth Cookie]
CreateCookie --- Step12[
<div style='text-align: center'>
<span style='display: inline-block; background-color: #6699cc !important; color:white; width: 28px; height: 28px; line-height: 28px; border-radius: 50%; font-weight: bold'>12</span>
<p style='margin-top: 8px'>Trả về Phản hồi</p>
</div>
]
Step12 --> Success[Trả về Thành công]
%% Styling
style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style FirebaseService fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style Database fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style AuthService fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ValidateRequest fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ExtractToken fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style FindUser fill:#f0f8e6,stroke:#339933,stroke-width:2px
style CheckRole fill:#f0f8e6,stroke:#339933,stroke-width:2px
style LoadData fill:#f0f8e6,stroke:#339933,stroke-width:2px
style CreateCookie fill:#f0f8e6,stroke:#339933,stroke-width:2px
style Success fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ReturnError fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style TokenCheck fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style UserCheck fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style RoleCheck fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style Step1 fill:transparent,stroke:transparent,stroke-width:1px
style Step2 fill:transparent,stroke:transparent,stroke-width:1px
style Step3 fill:transparent,stroke:transparent,stroke-width:1px
style Step4 fill:transparent,stroke:transparent,stroke-width:1px
style Step5 fill:transparent,stroke:transparent,stroke-width:1px
style Step6A fill:transparent,stroke:transparent,stroke-width:1px
style Step6B fill:transparent,stroke:transparent,stroke-width:1px
style Step7 fill:transparent,stroke:transparent,stroke-width:1px
style Step8A fill:transparent,stroke:transparent,stroke-width:1px
style Step8B fill:transparent,stroke:transparent,stroke-width:1px
style Step9 fill:transparent,stroke:transparent,stroke-width:1px
style Step10A fill:transparent,stroke:transparent,stroke-width:1px
style Step10B fill:transparent,stroke:transparent,stroke-width:1px
style Step11 fill:transparent,stroke:transparent,stroke-width:1px
style Step12 fill:transparent,stroke:transparent,stroke-width:1px
Tài liệu Trường hợp
Trường hợp 1: Đăng nhập Thành công
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as AuthController
participant Service as AuthService
participant Firebase
participant UserDB as users
participant AdminRoleDB as admin_roles
participant AdminRoleUserDB as admin_role_user
participant GroupDB as groups
participant GroupMemberDB as group_members
participant GroupRoleDB as group_roles
Note over Admin,API: Bước 1: Gửi Đăng nhập
Admin->>API: POST /api/v1/admin/auth/login (với firebase-token)
Note over API,Service: Bước 2: Xử lý Đăng nhập
API->>Service: login(token, data)
Note over Service,Firebase: Bước 3: Xác minh Token
Service->>Firebase: verifyIdToken(token)
Firebase-->>Service: Trả về thông tin user đã xác minh
Note over Service,UserDB: Bước 4: Tìm User
Service->>UserDB: findByUid(uid)
UserDB-->>Service: Trả về dữ liệu user
Note over Service,AdminRoleUserDB: Bước 5: Kiểm tra Vai trò Admin
Service->>AdminRoleUserDB: Kiểm tra Vai trò Admin
AdminRoleUserDB-->>Service: Trả về dữ liệu vai trò
Note over Service,GroupDB: Bước 6: Tải Dữ liệu Nhóm
Service->>GroupDB: Tải dữ liệu nhóm
GroupDB-->>Service: Trả về dữ liệu nhóm
Note over Service,GroupMemberDB: Bước 7: Tải Thành viên Nhóm
Service->>GroupMemberDB: Tải thành viên nhóm
GroupMemberDB-->>Service: Trả về dữ liệu thành viên nhóm
Note over Service,GroupRoleDB: Bước 8: Tải Vai trò Nhóm
Service->>GroupRoleDB: Tải vai trò nhóm
GroupRoleDB-->>Service: Trả về dữ liệu vai trò nhóm
Note over Service,API: Bước 9: Tạo Auth Cookie
Service->>Service: createAuthCookie(user)
Note over API,Admin: Bước 10: Trả về Phản hồi
API-->>Admin: 200 OK với dữ liệu user và cookies
Trường hợp 2: Đăng nhập Thất bại
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as AuthController
participant Service as AuthService
participant Firebase
participant UserDB as users
participant AdminRoleDB as admin_roles
Note over Admin,API: Bước 1: Gửi Đăng nhập
Admin->>API: POST /api/v1/admin/auth/login (với firebase-token)
Note over API,Service: Bước 2: Xử lý Đăng nhập
API->>Service: login(token, data)
Note over Service,Firebase: Bước 3: Xác minh Token
Service->>Firebase: verifyIdToken(token)
Firebase-->>Service: Trả về lỗi xác minh
Note over Service,API: Bước 4: Xử lý Lỗi
Service->>API: Trả về lỗi xác minh
Note over API,Admin: Bước 5: Trả về Phản hồi Lỗi
API-->>Admin: 401 Unauthorized với thông báo lỗi
Các Bước
Bước 1: Gửi Đăng nhập
- Mô tả: Admin gửi thông tin đăng nhập
- Yêu cầu:
POST /api/v1/admin/auth/login - Headers:
- firebase-token: Token từ xác thực Firebase
- Xác thực:
- Kiểm tra sự hiện diện của token
- Xác thực định dạng token
- Kiểm tra giới hạn tốc độ (5 lần/phút)
Bước 2: Xử lý Đăng nhập
- Mô tả: Controller xác thực yêu cầu và chuyển cho service
- Hành động:
- Trích xuất token từ header
- Gọi service xác thực cho quá trình đăng nhập
- Ghi log lần thử đăng nhập
Bước 3: Xác minh Token
- Mô tả: Xác minh tính xác thực của Firebase token
- Hành động:
- Gửi token đến Firebase để xác minh
- Trích xuất thông tin user từ token đã xác minh
- Xác nhận nhà cung cấp xác thực
Bước 4: Tìm User
- Mô tả: Tìm bản ghi user trong cơ sở dữ liệu
- Hành động:
- Truy vấn cơ sở dữ liệu cho user với Firebase UID khớp
- Xác minh user tồn tại và đang hoạt động
- Tải các mối quan hệ của user
Bước 5: Kiểm tra Vai trò Admin
- Mô tả: Xác minh user có quyền admin
- Hành động:
- Kiểm tra các vai trò được gán cho user
- Xác minh vai trò admin có mặt
- Xác thực quyền của vai trò
Bước 6: Tải Dữ liệu Nhóm
- Mô tả: Lấy dữ liệu liên quan đến nhóm
- Hành động:
- Truy vấn cơ sở dữ liệu cho dữ liệu nhóm
- Xác minh sự tồn tại của nhóm
- Tải các mối quan hệ của nhóm
Bước 7: Tải Thành viên Nhóm
- Mô tả: Lấy dữ liệu thành viên nhóm
- Hành động:
- Truy vấn cơ sở dữ liệu cho dữ liệu thành viên nhóm
- Xác minh sự tồn tại của thành viên nhóm
- Tải các mối quan hệ của thành viên nhóm
Bước 8: Tải Vai trò Nhóm
- Mô tả: Lấy dữ liệu vai trò nhóm
- Hành động:
- Truy vấn cơ sở dữ liệu cho dữ liệu vai trò nhóm
- Xác minh sự tồn tại của vai trò nhóm
- Tải các mối quan hệ của vai trò nhóm
Bước 9: Tạo Auth Cookie
- Mô tả: Tạo cookie phiên làm việc an toàn
- Hành động:
- Tạo token xác thực
- Tạo auth cookie với token:
Trend-Viewer_auth_api_token - Tạo cookie trạng thái đăng nhập:
Trend-Viewer_is_logged_in - Đặt cờ secure và httpOnly
- Đặt domain và path phù hợp
Bước 10: Trả về Phản hồi
- Mô tả: Gửi phản hồi thành công cho client
- Phản hồi:
- Thành công:
200 OKvới dữ liệu user - Đặt cookies trong phản hồi
- Bao gồm chi tiết user trong body phản hồi
- Thành công:
API Endpoint
Endpoint: POST /api/v1/admin/auth/login
Headers:
firebase-token: Token xác thực từ Firebase (bắt buộc)
Body Parameters:
- Không có (tất cả thông tin xác thực được truyền qua header)
Response:
{
"success": true,
"message": "Đăng nhập thành công",
"data": {
"user": {
"id": 1,
"name": "Admin User",
"email": "admin@example.com",
"uid": "firebase_uid_here",
"status": 1,
"is_first_login": false,
"created_at": "2024-01-01T00:00:00.000000Z",
"updated_at": "2024-01-01T00:00:00.000000Z"
},
"admin_roles": [
{
"id": 1,
"name": "Super Admin",
"slug": "super_admin"
}
],
"groups": [
{
"id": 1,
"name": "Default Group",
"group_members": [...],
"group_roles": [...]
}
]
}
}
Bảng Cơ sở Dữ liệu Liên quan & Trường
erDiagram
users {
bigint id PK
string name "Tên đầy đủ của user"
string email "Địa chỉ email của user (duy nhất)"
string uid "Firebase user ID (duy nhất)"
int status "Trạng thái tài khoản: 1: hoạt động, 0: không hoạt động"
boolean is_first_login "Cờ cho biết user đã hoàn thành đăng nhập lần đầu"
timestamp created_at
timestamp updated_at
}
roles {
bigint id PK
string name "Tên hiển thị vai trò"
string slug "Định danh vai trò cho quyền (duy nhất)"
timestamp created_at
timestamp updated_at
}
admin_role_user {
bigint user_id FK "Tham chiếu đến bảng users"
bigint role_id FK "Tham chiếu đến bảng roles"
timestamp created_at
timestamp updated_at
}
groups {
bigint id PK
string name "Tên nhóm"
string description "Mô tả nhóm"
int status "Trạng thái nhóm: 1: hoạt động, 0: không hoạt động"
timestamp created_at
timestamp updated_at
}
group_members {
bigint id PK
bigint group_id FK "Tham chiếu đến bảng groups"
bigint user_id FK "Tham chiếu đến bảng users"
int status "Trạng thái thành viên: 1: hoạt động, 0: không hoạt động"
timestamp created_at
timestamp updated_at
}
group_roles {
bigint id PK
bigint group_id FK "Tham chiếu đến bảng groups"
bigint user_id FK "Tham chiếu đến bảng users"
string role "Vai trò trong nhóm"
timestamp created_at
timestamp updated_at
}
users ||--o{ admin_role_user : has
roles ||--o{ admin_role_user : has
users ||--o{ group_members : belongs_to
groups ||--o{ group_members : contains
users ||--o{ group_roles : has_role_in
groups ||--o{ group_roles : assigns_role
Xử lý Lỗi
-
Ghi log
- Các lần đăng nhập thất bại được ghi vào log ứng dụng
- Lỗi xác minh vai trò được ghi lại
- (Tùy chọn) Gửi tin nhắn slack cho các sự kiện bảo mật
-
Chi tiết Lỗi:
Mã Trạng thái Thông báo Lỗi Mô tả 401 "Thông tin đăng nhập không chính xác." Khi thông tin đăng nhập không hợp lệ 403 "Không có quyền quản trị." Khi user thiếu vai trò admin 429 "Quá nhiều yêu cầu." Khi vượt quá giới hạn tốc độ 401 Lỗi chung với thông báo exception Khi xảy ra lỗi không mong đợi
Ghi chú Bổ sung
- Giới hạn tốc độ: Các lần thử đăng nhập admin bị giới hạn ở 5 lần/phút cho mỗi địa chỉ IP
- Thời gian hết hạn phiên làm việc: Phiên làm việc admin hết hạn sau 8 giờ không hoạt động
- Bảo mật: Hệ thống sử dụng Firebase authentication để đảm bảo tính bảo mật cao
- Kiểm tra vai trò: Chỉ những user có vai trò admin mới có thể truy cập
- Ghi log: Tất cả các lần đăng nhập admin đều được ghi lại để kiểm tra bảo mật
- Cân nhắc triển khai:
- Xác thực hai yếu tố cho quyền truy cập admin
- Hạn chế truy cập dựa trên IP
- Giám sát hoạt động và cảnh báo
- Theo dõi hoạt động phiên làm việc