- Added endpoints for sending and confirming email verification, enhancing user account security. - Integrated two-factor authentication (2FA) with TOTP support, including enabling, verifying, and disabling 2FA. - Implemented social login functionality for Google and Facebook, allowing users to authenticate using their existing accounts. - Updated dependency injection to include services for email, 2FA, and social login. - Enhanced documentation to reflect new features and usage examples for email verification and 2FA.
10 KiB
10 KiB
Hướng Dẫn Xác Thực IAM Service
Hướng dẫn đầy đủ về xác thực sử dụng GoodGo IAM Service với OAuth2/OpenID Connect.
Tổng Quan
IAM Service cung cấp xác thực OAuth2/OIDC sử dụng Duende IdentityServer:
- Password Grant - Đăng nhập user với email/password
- Refresh Token - Làm mới token mà không cần xác thực lại
- Client Credentials - Xác thực service-to-service
- Email Verification - Xác minh email qua SMTP
- Two-Factor Authentication (2FA) - TOTP với QR code và recovery codes
- Social Login - Tích hợp OAuth Google và Facebook
Bắt Đầu Nhanh
1. Đăng Ký User
curl -X POST http://localhost:5001/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123!",
"firstName": "John",
"lastName": "Doe"
}'
2. Đăng Nhập (Lấy Tokens)
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=Password123!" \
-d "scope=openid profile email offline_access"
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email offline_access"
}
3. Sử Dụng Access Token
curl http://localhost:5001/api/v1/users/me \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
Các Loại OAuth2 Grant
Password Grant (Đăng Nhập User)
Cho các ứng dụng đáng tin cậy nơi users nhập thông tin đăng nhập trực tiếp.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=Password123!" \
-d "scope=openid profile email offline_access"
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
grant_type |
Có | Phải là password |
username |
Có | Email của user |
password |
Có | Mật khẩu của user |
scope |
Không | Các scopes cách nhau bằng dấu cách |
Refresh Token
Làm mới access token mà không cần nhập lại thông tin đăng nhập.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=eyJhbGciOiJSUzI1NiIs..."
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
grant_type |
Có | Phải là refresh_token |
refresh_token |
Có | Refresh token hợp lệ |
Client Credentials (Service-to-Service)
Cho các backend services xác thực mà không cần user context.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=goodgo-service" \
-d "client_secret=service-secret" \
-d "scope=api"
| Tham số | Bắt buộc | Mô tả |
|---|---|---|
grant_type |
Có | Phải là client_credentials |
client_id |
Có | Client ID đã đăng ký |
client_secret |
Có | Client secret |
scope |
Không | Các scopes yêu cầu |
Lưu ý: Client applications phải được đăng ký trong database trước khi sử dụng.
Thời Hạn Token
| Loại Token | Thời hạn | Sử dụng |
|---|---|---|
| Access Token | 15 phút | API authorization |
| Refresh Token | 7 ngày | Làm mới token |
Các Scopes Hỗ Trợ
| Scope | Mô tả |
|---|---|
openid |
Bắt buộc cho OIDC |
profile |
Thông tin profile (tên) |
email |
Email của user |
roles |
Các roles của user |
offline_access |
Nhận refresh token |
api |
Truy cập API |
API Endpoints
Xác Thực
| Method | Endpoint | Mô tả |
|---|---|---|
POST |
/api/v1/auth/register |
Đăng ký user mới |
POST |
/connect/token |
OAuth2 token endpoint |
POST |
/api/v1/auth/change-password |
Đổi mật khẩu (cần auth) |
POST |
/api/v1/auth/logout |
Thu hồi tokens (cần auth) |
Xác Minh Email
| Method | Endpoint | Mô tả |
|---|---|---|
POST |
/api/v1/auth/send-verification-email |
Gửi link xác minh email (cần auth) |
POST |
/api/v1/auth/confirm-email |
Xác nhận email với token |
Xác Thực Hai Yếu Tố (2FA)
| Method | Endpoint | Mô tả |
|---|---|---|
POST |
/api/v1/auth/2fa/enable |
Bật 2FA (lấy QR code) (cần auth) |
POST |
/api/v1/auth/2fa/verify |
Xác minh mã TOTP & kích hoạt (cần auth) |
POST |
/api/v1/auth/2fa/disable |
Tắt 2FA (cần auth) |
Đăng Nhập Mạng Xã Hội
| Method | Endpoint | Mô tả |
|---|---|---|
GET |
/api/v1/auth/external-login/{provider} |
Khởi tạo OAuth flow (Google/Facebook) |
GET |
/api/v1/auth/external-callback |
Xử lý OAuth callback |
GET |
/api/v1/auth/linked-accounts |
Lấy danh sách OAuth providers đã liên kết (cần auth) |
Quản Lý User
| Method | Endpoint | Mô tả |
|---|---|---|
GET |
/api/v1/users |
Danh sách users (phân trang) |
GET |
/api/v1/users/me |
Thông tin user hiện tại |
GET |
/api/v1/users/{id} |
Lấy user theo ID |
PUT |
/api/v1/users/{id} |
Cập nhật user |
DELETE |
/api/v1/users/{id} |
Xóa user (soft) |
Ví Dụ Tích Hợp
JavaScript/TypeScript
// Đăng nhập
const response = await fetch('http://localhost:5001/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'password',
username: 'user@example.com',
password: 'Password123!',
scope: 'openid profile email offline_access'
})
});
const { access_token, refresh_token } = await response.json();
// Sử dụng token
const user = await fetch('http://localhost:5001/api/v1/users/me', {
headers: { 'Authorization': `Bearer ${access_token}` }
}).then(r => r.json());
C# / .NET
// Đăng nhập
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["username"] = "user@example.com",
["password"] = "Password123!",
["scope"] = "openid profile email offline_access"
});
var response = await client.PostAsync("http://localhost:5001/connect/token", content);
var tokens = await response.Content.ReadFromJsonAsync<TokenResponse>();
// Sử dụng token
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
var user = await client.GetFromJsonAsync<UserDto>("/api/v1/users/me");
Xác Minh Email
Gửi Email Xác Minh
curl -X POST http://localhost:5001/api/v1/auth/send-verification-email \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Xác Nhận Email
curl -X POST http://localhost:5001/api/v1/auth/confirm-email \
-H "Content-Type: application/json" \
-d '{"userId": "user-guid", "token": "confirmation-token"}'
Xác Thực Hai Yếu Tố (2FA)
Bật 2FA
curl -X POST http://localhost:5001/api/v1/auth/2fa/enable \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"success": true,
"data": {
"secretKey": "JBSWY3DPEHPK3PXP",
"qrCodeBase64": "data:image/png;base64,...",
"recoveryCodes": ["code1", "code2", "code3"]
}
}
Xác Minh Mã 2FA
curl -X POST http://localhost:5001/api/v1/auth/2fa/verify \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Tắt 2FA
curl -X POST http://localhost:5001/api/v1/auth/2fa/disable \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Đăng Nhập Mạng Xã Hội
Khởi Tạo OAuth Flow
Chuyển hướng user đến:
GET http://localhost:5001/api/v1/auth/external-login/Google?returnUrl=http://your-app/callback
GET http://localhost:5001/api/v1/auth/external-login/Facebook?returnUrl=http://your-app/callback
Lấy Danh Sách Tài Khoản Liên Kết
curl http://localhost:5001/api/v1/auth/linked-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"success": true,
"data": {
"linkedProviders": [
{"provider": "Google", "providerDisplayName": "Google"},
{"provider": "Facebook", "providerDisplayName": "Facebook"}
]
}
}
Xử Lý Lỗi
Các Lỗi Thường Gặp
| Lỗi | HTTP Code | Mô tả |
|---|---|---|
invalid_grant |
400 | Thông tin đăng nhập không hợp lệ |
invalid_client |
400 | client_id không xác định |
invalid_scope |
400 | Scope yêu cầu không hợp lệ |
unauthorized |
401 | Token không hợp lệ/hết hạn |
Định Dạng Lỗi
{
"error": "invalid_grant",
"error_description": "The username or password is incorrect."
}
Best Practices Bảo Mật
- Lưu trữ tokens an toàn - Sử dụng httpOnly cookies hoặc secure storage
- Làm mới tokens chủ động - Trước khi access token hết hạn
- Sử dụng HTTPS trong production - Không bao giờ gửi credentials qua HTTP
- Đăng xuất đúng cách - Gọi logout endpoint để thu hồi tokens
- Validate tokens phía server - Không tin tưởng validation phía client
Swagger UI
Truy cập tài liệu API tương tác: