Quản lý Mật khẩu Admin
Mô tả Tổng quan
Tính năng Quản lý Mật khẩu Admin cung cấp khả năng đặt lại mật khẩu cho tài khoản quản trị một cách an toàn. Tính năng này bao gồm hai quy trình chính: yêu cầu đặt lại mật khẩu (gửi email với link đặt lại) và thực hiện đặt lại mật khẩu (sử dụng token xác minh). Hệ thống đảm bảo tính bảo mật cao bằng cách sử dụng token có thời gian hết hạn ngắn và ghi lại tất cả các hoạt động liên quan đến mật khẩu.
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]
PasswordController[PasswordController]
PasswordService[PasswordService]
EmailService[Email Service]
TokenDB[(Token Store)]
UserDB[(User 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'>Yêu cầu Đặt lại</p>
</div>
]
Step1 --> ValidateEmail[Xác thực Email]
ValidateEmail --- 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'>Kiểm tra User</p>
</div>
]
Step2 --> CheckUser[Kiểm tra User trong Database]
CheckUser --- 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ạo Token</p>
</div>
]
Step3 --> GenerateToken[Tạo Token Đặt lại]
GenerateToken --- 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'>Lưu Token</p>
</div>
]
Step4 --> StoreToken[Lưu Token vào Database]
StoreToken --- 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'>Gửi Email</p>
</div>
]
Step5 --> SendEmail[Gửi Email với Link]
SendEmail --- 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'>Trả về Phản hồi</p>
</div>
]
Step6 --> Success[Trả về Thành công]
%% Reset Password Flow
AdminUser --- 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'>Nhập Mật khẩu Mới</p>
</div>
]
Step7 --> ValidateToken[Xác thực Token]
ValidateToken --- 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'>Kiểm tra Hợp lệ</p>
</div>
]
Step8 --> TokenValid{Token Hợp lệ?}
TokenValid --- Step9A[
<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'>9A</span>
<p style='margin-top: 8px'>Trả về Lỗi</p>
</div>
]
Step9A -->|Không| ReturnError[Trả về Lỗi]
TokenValid --- Step9B[
<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'>9B</span>
<p style='margin-top: 8px'>Cập nhật Mật khẩu</p>
</div>
]
Step9B -->|Có| UpdatePassword[Cập nhật Mật khẩu]
UpdatePassword --- 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'>Xóa Token</p>
</div>
]
Step10 --> ClearToken[Xóa Token đã sử dụng]
ClearToken --- 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'>Ghi log</p>
</div>
]
Step11 --> LogReset[Ghi log Đặt lại Mật khẩu]
LogReset --- 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 --> ResetSuccess[Trả về Thành công]
%% Styling
style AdminUser fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style PasswordController fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style PasswordService fill:#f0f8e6,stroke:#339933,stroke-width:2px
style EmailService fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style TokenDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style UserDB fill:#ffe6cc,stroke:#ff9900,stroke-width:2px
style ValidateEmail fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style CheckUser fill:#f0f8e6,stroke:#339933,stroke-width:2px
style GenerateToken fill:#f0f8e6,stroke:#339933,stroke-width:2px
style StoreToken fill:#f0f8e6,stroke:#339933,stroke-width:2px
style SendEmail fill:#f0f8e6,stroke:#339933,stroke-width:2px
style Success fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ValidateToken fill:#f0f8e6,stroke:#339933,stroke-width:2px
style UpdatePassword fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ClearToken fill:#f0f8e6,stroke:#339933,stroke-width:2px
style LogReset fill:#f0f8e6,stroke:#339933,stroke-width:2px
style ResetSuccess fill:#e6f3ff,stroke:#0066cc,stroke-width:2px
style ReturnError fill:#fcd9d9,stroke:#cc3333,stroke-width:2px
style TokenValid 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 Step6 fill:transparent,stroke:transparent,stroke-width:1px
style Step7 fill:transparent,stroke:transparent,stroke-width:1px
style Step8 fill:transparent,stroke:transparent,stroke-width:1px
style Step9A fill:transparent,stroke:transparent,stroke-width:1px
style Step9B fill:transparent,stroke:transparent,stroke-width:1px
style Step10 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: Yêu cầu Đặt lại Mật khẩu
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as PasswordController
participant Service as PasswordService
participant UserDB as Database
participant TokenDB as Database
participant EmailService as Email
Note over Admin,API: Bước 1: Gửi Yêu cầu Đặt lại
Admin->>API: POST /api/v1/admin/auth/forgot (với email)
Note over API,Service: Bước 2: Xử lý Yêu cầu
API->>Service: sendResetLink(email)
Note over Service,UserDB: Bước 3: Tìm User
Service->>UserDB: findByEmail(email)
UserDB-->>Service: Trả về dữ liệu user
Note over Service,Service: Bước 4: Tạo Token
Service->>Service: generateResetToken()
Note over Service,TokenDB: Bước 5: Lưu Token
Service->>TokenDB: storeResetToken(user_id, token)
TokenDB-->>Service: Xác nhận lưu
Note over Service,EmailService: Bước 6: Gửi Email
Service->>EmailService: sendResetEmail(email, token)
EmailService-->>Service: Xác nhận gửi
Note over API,Admin: Bước 7: Trả về Phản hồi
API-->>Admin: 200 OK với thông báo gửi email
Trường hợp 2: Đặt lại Mật khẩu với Token
Biểu đồ Tuần tự
sequenceDiagram
participant Admin
participant API as PasswordController
participant Service as PasswordService
participant TokenDB as Database
participant UserDB as Database
Note over Admin,API: Bước 1: Gửi Token và Mật khẩu Mới
Admin->>API: POST /api/v1/admin/auth/reset (với token, password)
Note over API,Service: Bước 2: Xử lý Đặt lại
API->>Service: resetPassword(token, password)
Note over Service,TokenDB: Bước 3: Xác minh Token
Service->>TokenDB: validateResetToken(token)
TokenDB-->>Service: Trả về thông tin token
Note over Service,Service: Bước 4: Kiểm tra Hợp lệ
Service->>Service: validateToken(token_info)
Note over Service,UserDB: Bước 5: Cập nhật Mật khẩu
Service->>UserDB: updatePassword(user_id, password)
UserDB-->>Service: Xác nhận cập nhật
Note over Service,TokenDB: Bước 6: Xóa Token
Service->>TokenDB: deleteResetToken(token)
TokenDB-->>Service: Xác nhận xóa
Note over API,Admin: Bước 7: Trả về Phản hồi
API-->>Admin: 200 OK với thông báo đặt lại thành công
Các Bước
Quy trình Yêu cầu Đặt lại Mật khẩu
Bước 1: Gửi Yêu cầu Đặt lại
- Mô tả: Admin gửi yêu cầu đặt lại mật khẩu
- Yêu cầu:
POST /api/v1/admin/auth/forgot - Body Parameters:
- email: Địa chỉ email của tài khoản admin (bắt buộc)
- Xác thực:
- Kiểm tra định dạng email
- Kiểm tra giới hạn tốc độ (3 lần/phút)
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 thực định dạng email
- Gọi service mật khẩu cho quá trình đặt lại
- Ghi log yêu cầu đặt lại
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 email khớp
- Xác minh user tồn tại và có vai trò admin
- Kiểm tra trạng thái tài khoản
Bước 4: Tạo Token
- Mô tả: Tạo token đặt lại mật khẩu an toàn
- Hành động:
- Tạo token ngẫu nhiên 64 ký tự
- Đặt thời gian hết hạn (1 giờ)
- Mã hóa token trước khi lưu
Bước 5: Lưu Token
- Mô tả: Lưu token vào cơ sở dữ liệu
- Hành động:
- Lưu token đã mã hóa
- Liên kết với user_id
- Đặt thời gian hết hạn
Bước 6: Gửi Email
- Mô tả: Gửi email với link đặt lại mật khẩu
- Hành động:
- Tạo link đặt lại với token
- Gửi email đến địa chỉ đã đăng ký
- Ghi log việc gửi email
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 thông báo gửi email - Không tiết lộ thông tin về sự tồn tại của email
- Thành công:
Quy trình Đặt lại Mật khẩu
Bước 1: Gửi Token và Mật khẩu Mới
- Mô tả: Admin gửi token và mật khẩu mới
- Yêu cầu:
POST /api/v1/admin/auth/reset - Body Parameters:
- token: Token đặt lại mật khẩu (bắt buộc)
- password: Mật khẩu mới (bắt buộc)
- password_confirmation: Xác nhận mật khẩu (bắt buộc)
Bước 2: Xử lý Đặt lại
- Mô tả: Controller xác thực yêu cầu và chuyển cho service
- Hành động:
- Xác thực mật khẩu mới
- Gọi service mật khẩu cho quá trình đặt lại
- Ghi log yêu cầu đặt lại
Bước 3: Xác minh Token
- Mô tả: Xác minh tính hợp lệ của token
- Hành động:
- Tìm token trong cơ sở dữ liệu
- Kiểm tra thời gian hết hạn
- Xác minh token chưa được sử dụng
Bước 4: Kiểm tra Hợp lệ
- Mô tả: Kiểm tra các điều kiện hợp lệ
- Hành động:
- Kiểm tra token còn hiệu lực
- Xác thực mật khẩu mới đáp ứng yêu cầu
- Kiểm tra mật khẩu xác nhận khớp
Bước 5: Cập nhật Mật khẩu
- Mô tả: Cập nhật mật khẩu mới cho user
- Hành động:
- Mã hóa mật khẩu mới
- Cập nhật trong cơ sở dữ liệu
- Ghi log thay đổi mật khẩu
Bước 6: Xóa Token
- Mô tả: Xóa token đã sử dụng
- Hành động:
- Xóa token khỏi cơ sở dữ liệu
- Đảm bảo token không thể sử dụng lại
- Ghi log việc xóa token
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 thông báo đặt lại thành công - Xác nhận mật khẩu đã được thay đổi
- Thành công:
API Endpoints
1. Yêu cầu Đặt lại Mật khẩu
Endpoint: POST /api/v1/admin/auth/forgot
Headers:
Content-Type:application/json
Body Parameters:
{
"email": "admin@example.com"
}
Response:
{
"success": true,
"message": "Email đặt lại mật khẩu đã được gửi",
"data": {
"email_sent": true,
"expires_in": "1 giờ"
}
}
2. Đặt lại Mật khẩu
Endpoint: POST /api/v1/admin/auth/reset
Headers:
Content-Type:application/json
Body Parameters:
{
"token": "reset_token_here",
"password": "new_password123",
"password_confirmation": "new_password123"
}
Response:
{
"success": true,
"message": "Mật khẩu đã được đặt lại thành công",
"data": {
"password_updated": true,
"updated_at": "2024-01-01T08:00:00.000000Z"
}
}
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)"
string password "Mật khẩu đã mã hóa (cho admin)"
int status "Trạng thái tài khoản: 1: hoạt động, 0: không hoạt động"
timestamp created_at
timestamp updated_at
}
password_resets {
bigint id PK
string email "Địa chỉ email của user"
string token "Token đặt lại mật khẩu đã mã hóa"
timestamp expires_at "Thời gian hết hạn token"
boolean is_used "Trạng thái sử dụng: 0: chưa sử dụng, 1: đã sử dụng"
timestamp created_at
timestamp updated_at
}
password_change_logs {
bigint id PK
bigint user_id FK "Tham chiếu đến bảng users"
string change_type "Loại thay đổi: reset, update"
string ip_address "Địa chỉ IP của user"
timestamp changed_at "Thời gian thay đổi"
timestamp created_at
}
users ||--o{ password_change_logs : logs
password_resets ||--o{ users : belongs_to
Xử lý Lỗi
-
Ghi log
- Tất cả các yêu cầu đặt lại mật khẩu được ghi vào log ứng dụng
- Lỗi xác minh token đượ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ả 400 "Email không hợp lệ." Khi định dạng email không đúng 404 "Email không tồn tại." Khi email không có trong hệ thống 429 "Quá nhiều yêu cầu." Khi vượt quá giới hạn tốc độ 400 "Token không hợp lệ hoặc đã hết hạn." Khi token không hợp lệ 400 "Mật khẩu xác nhận không khớp." Khi mật khẩu xác nhận sai 422 "Mật khẩu không đáp ứng yêu cầu." Khi mật khẩu quá yếu 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 đặt lại mật khẩu bị giới hạn ở 3 lần/phút cho mỗi địa chỉ IP
- Thời gian hết hạn token: Token đặt lại mật khẩu hết hạn sau 1 giờ
- Bảo mật: Token được mã hóa trước khi lưu vào cơ sở dữ liệu
- Email: Hệ thống gửi email với link đặt lại mật khẩu an toàn
- Ghi log: Tất cả các hoạt động liên quan đến mật khẩu đều được ghi lại
- Yêu cầu mật khẩu: Mật khẩu mới phải đáp ứng các yêu cầu bảo mật
- Cân nhắc triển khai:
- Gửi email thông báo khi mật khẩu được thay đổi
- Yêu cầu đăng nhập lại sau khi đặt lại mật khẩu
- Theo dõi các lần thay đổi mật khẩu bất thường
- Triển khai xác thực hai yếu tố cho admin