Đăng nhập Đại diện
Mô tả Tổng quan
Tính năng Đăng nhập Đại diện cho phép quản trị viên đăng nhập với tư cách đại diện của một thành viên nhóm cụ thể. Điều này rất hữu ích cho việc hỗ trợ kỹ thuật, kiểm tra vấn đề từ góc nhìn của user, hoặc thực hiện các hành động thay mặt user khi cần thiết. Tính năng này đảm bảo rằng chỉ những quản trị viên có quyền hạn phù hợp mới có thể sử dụng chức năng này và tất cả các hành động đều được ghi lại để kiểm tra.
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]
RepresentativeController[RepresentativeController]
AuthService[AuthService]
UserDB[(Database)]
SessionDB[(Session Store)]
%% 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'>Yêu cầu Đại diện</p>
</div>
]
Step1 --> ValidateAdmin[Xác thực Admin]
ValidateAdmin --- Step2[
<div 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'>Kiểm tra Quyền</p>
</div>
]
Step2 --> CheckPermissions[Kiểm tra Quyền Admin]
CheckPermissions --- 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'>Tìm User</p>
</div>
]
Step3 --> FindUser[Tìm User trong Database]
FindUser --- 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'>Kiểm tra Sự tồn tại</p>
</div>
]
Step4 --> UserCheck{User Tồn tại?}
UserCheck --- Step5A[
<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'>5A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step5A -->|Không| ReturnError[Trả về Lỗi]
UserCheck --- Step5B[
<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'>5B</span>
<p style='margin-top: 8px'>Kiểm tra Nhóm</p>
</div>
]
Step5B -->|Có| CheckGroup[Kiểm tra Thành viên Nhóm]
CheckGroup --- Step6[
<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'>6</span>
<p style='margin-top: 8px'>Xác minh Quyền</p>
</div>
]
Step6 --> GroupCheck{Thuộc Nhóm?}
GroupCheck --- Step7A[
<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'>7A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step7A -->|Không| ReturnError
GroupCheck --- Step7B[
<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'>7B</span>
<p style='margin-top: 8px'>Tạo Phiên làm việc</p>
</div>
]
Step7B -->|Có| CreateSession[Tạo Phiên làm việc Đại diện]
CreateSession --- Step8[
<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'>8</span>
<p style='margin-top: 8px'>Lưu Phiên làm việc</p>
</div>
]
Step8 --> StoreSession[Lưu vào Session Store]
StoreSession --- 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'>Tạo Cookie</p>
</div>
]
Step9 --> GenerateCookie[Tạo Representative Cookie]
GenerateCookie --- Step10[
<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'>10</span>
<p style='margin-top: 8px'>Trả về Phản hồi</p>
</div>
]
Step10 --> Success[Trả về Thành công]
%% Styling
style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style RepresentativeController fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style AuthService fill:#f0f8e6,stroke:#339933,stroke-width:2px
style UserDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style SessionDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style ValidateAdmin fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style CheckPermissions fill:#f0f8e6,stroke:#339933,stroke-width:2px
style FindUser fill:#f0f8e6,stroke:#339933,stroke-width:2px
style CheckGroup fill:#f0f8e6,stroke:#339933,stroke-width:2px
style CreateSession fill:#f0f8e6,stroke:#339933,stroke-width:2px
style StoreSession fill:#f0f8e6,stroke:#339933,stroke-width:2px
style GenerateCookie 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 UserCheck fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style GroupCheck 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 Step5A fill:transparent,stroke:transparent,stroke-width:1px
style Step5B fill:transparent,stroke:transparent,stroke-width:1px
style Step6 fill:transparent,stroke:transparent,stroke-width:1px
style Step7A fill:transparent,stroke:transparent,stroke-width:1px
style Step7B fill:transparent,stroke:transparent,stroke-width:1px
style Step8 fill:transparent,stroke:transparent,stroke-width:1px
style Step9 fill:transparent,stroke:transparent,stroke-width:1px
style Step10 fill:transparent,stroke:transparent,stroke-width:1px
Tài liệu Trường hợp
Trường hợp 1: Đăng nhập Đại diện Thành công
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as RepresentativeController
participant Service as AuthService
participant UserDB as Database
participant SessionDB as Database
Note over Admin,API: Bước 1: Gửi Yêu cầu Đại diện
Admin->>API: POST /api/v1/admin/auth/representative (với user_id)
Note over API,Service: Bước 2: Xử lý Yêu cầu
API->>Service: loginAsRepresentative(user_id)
Note over Service,UserDB: Bước 3: Tìm User
Service->>UserDB: findUserWithGroup(user_id)
UserDB-->>Service: Trả về dữ liệu user
Note over Service,Service: Bước 4: Kiểm tra Quyền
Service->>Service: validateRepresentativeAccess(user_id)
Note over Service,SessionDB: Bước 5: Tạo Phiên làm việc
Service->>SessionDB: createRepresentativeSession(admin_id, user_id)
SessionDB-->>Service: Trả về dữ liệu phiên làm việc
Note over Service,Service: Bước 6: Tạo Cookie
Service->>Service: generateRepresentativeCookie
Note over API,Admin: Bước 7: Trả về Phản hồi
API-->>Admin: 200 OK với cookies
Trường hợp 2: Đăng nhập Đại diện Thất bại
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as RepresentativeController
participant Service as AuthService
participant UserDB as Database
Note over Admin,API: Bước 1: Gửi Yêu cầu Đại diện
Admin->>API: POST /api/v1/admin/auth/representative (với user_id)
Note over API,Service: Bước 2: Xử lý Yêu cầu
API->>Service: loginAsRepresentative(user_id)
Note over Service,UserDB: Bước 3: Tìm User
Service->>UserDB: findUserWithGroup(user_id)
UserDB-->>Service: Trả về lỗi - User không tồn tại
Note over Service,API: Bước 4: Xử lý Lỗi
Service->>API: Trả về lỗi user không tồn tại
Note over API,Admin: Bước 5: Trả về Phản hồi Lỗi
API-->>Admin: 404 Not Found với thông báo lỗi
Các Bước
Bước 1: Gửi Yêu cầu Đại diện
- Mô tả: Admin thực hiện thao tác đăng nhập với vai trò đại diện cho user khác. Nếu muốn quay lại quyền admin, truyền giá trị đặc biệt
0. - Yêu cầu:
POST /api/admin/auth/representative/{id} - Tham số URL:
id: ID của user cần đại diện, hoặc0để trở lại quyền admin
- Xác thực:
- Kiểm tra xác thực admin
- Xác minh quyền sử dụng tính năng đại diện
- Kiểm tra giới hạn tốc độ
Bước 2: Xử lý Yêu cầu
- Mô tả: Controller xác thực yêu cầu và chuyển cho service
- Hành động:
- Xác minh quyền admin
- Trích xuất user_id từ body
- Gọi service xác thực cho quá trình đại diện
Bước 3: 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 ID khớp
- Xác minh user tồn tại và đang hoạt động
- Tải thông tin nhóm của user
Bước 4: Kiểm tra Quyền
- Mô tả: Xác minh quyền truy cập đại diện
- Hành động:
- Kiểm tra user có thuộc nhóm hợp lệ
- Xác minh quyền admin có thể đại diện cho user này
- Kiểm tra các ràng buộc bảo mật
Bước 5: Tạo Phiên làm việc
- Mô tả: Tạo phiên làm việc đại diện
- Hành động:
- Tạo định danh phiên làm việc duy nhất
- Liên kết admin và user đại diện
- Đặt thời gian hết hạn phiên làm việc
- Ghi log quyền truy cập đại diện
Bước 6: Tạo Cookie
- Mô tả: Tạo cookie phiên làm việc đại diện
- Hành động:
- Tạo token đại diện an toàn
- Tạo cookie với cờ secure và httpOnly
- Đặt domain và path phù hợp
- Đặt thời gian hết hạn
Bước 7: Trả về Phản hồi
- Mô tả: Gửi phản hồi thành công
- Phản hồi:
- Thành công:
200 OKvới dữ liệu user - Đặt cookie đại diện
- Bao gồm thông tin phiên làm việc
- Thành công:
API Endpoint
Endpoint: POST /api/admin/auth/representative/{id}
Headers:
firebase-token: Token xác thực từ Firebase (bắt buộc)Content-Type:application/json
Body Parameters:
{
"user_id": 123
}
Response:
{
"success": true,
"message": "Đăng nhập đại diện thành công",
"data": {
"representative_user": {
"id": 123,
"name": "User Name",
"email": "user@example.com",
"uid": "firebase_uid_here",
"status": 1,
"groups": [
{
"id": 1,
"name": "Default Group",
"role": "member"
}
]
},
"session_info": {
"representative_session_id": "session_uuid_here",
"expires_at": "2024-01-01T08:00:00.000000Z",
"admin_user_id": 1
}
}
}
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
}
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
}
representative_sessions {
bigint id PK
bigint admin_user_id FK "Tham chiếu đến bảng users (admin)"
bigint representative_user_id FK "Tham chiếu đến bảng users (đại diện)"
string session_id "Định danh phiên làm việc duy nhất"
timestamp expires_at "Thời gian hết hạn phiên làm việc"
timestamp created_at
timestamp updated_at
}
users ||--o{ group_members : belongs_to
groups ||--o{ group_members : contains
users ||--o{ group_roles : has_role_in
groups ||--o{ group_roles : assigns_role
users ||--o{ representative_sessions : admin_creates
users ||--o{ representative_sessions : is_represented
Xử lý Lỗi
-
Ghi log
- Tất cả các yêu cầu đại diện được ghi vào log ứng dụng
- Lỗi xác minh quyền đượ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 "Không được phép truy cập." Khi không có quyền admin 404 "User không tồn tại." Khi user_id không hợp lệ 403 "Không thể đại diện cho user này." Khi user không thuộc nhóm hợp lệ 429 "Quá nhiều yêu cầu." Khi vượt quá giới hạn tốc độ 500 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 yêu cầu đại diện bị giới hạn ở 10 lần/phút cho mỗi admin
- Thời gian hết hạn phiên làm việc: Phiên làm việc đại diện hết hạn sau 1 giờ
- Bảo mật: Tất cả các hành động đại diện đều được ghi lại để kiểm tra
- Kiểm tra quyền: Chỉ những admin có quyền hạn phù hợp mới có thể sử dụng
- Ghi log: Tất cả các lần đăng nhập đại diện đều được ghi lại để kiểm tra bảo mật
- Cân nhắc triển khai:
- Giới hạn số lượng phiên làm việc đại diện đồng thời
- Cảnh báo khi admin sử dụng quyền đại diện
- Theo dõi hoạt động đại diện
- Tự động kết thúc phiên làm việc không hoạt động