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: