Files
pos-system/services/iam-service-net/docs/vi
Ho Ngoc Hai 928a22fe3e feat(authentication): Implement email verification, two-factor authentication, and social login features
- 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.
2026-01-12 23:07:53 +07:00
..

IAM Service .NET 10

Service IAM (Identity and Access Management) .NET 10 với OAuth2/OIDC sử dụng Duende IdentityServer.

Tổng Quan

IAM Service cung cấp các chức năng quản lý danh tính và truy cập:

  • OAuth2/OIDC - Authentication với Duende IdentityServer
  • User Management - CRUD operations cho users
  • Password Management - Đổi mật khẩu
  • Token Management - Issue, refresh, revoke tokens
  • Email Verification - Xác thực email qua SMTP
  • 2FA/MFA - Xác thực hai yếu tố với TOTP
  • Social Login - Đăng nhập qua Google và Facebook
  • CQRS Pattern - MediatR cho Commands/Queries
  • Clean Architecture - Domain, Infrastructure, API layers

Yêu Cầu

Yêu cầu Phiên bản
.NET SDK 10.0.101+
Docker 24.0+
PostgreSQL 15+

Bắt Đầu Nhanh

Chạy với Docker

cd deployments/local
docker-compose up -d

Chạy Local

cd services/iam-service-net
dotnet restore
dotnet build
dotnet run --project src/IamService.API

Database Migrations

Yêu Cầu

# Cài đặt EF Core tools (một lần)
dotnet tool install --global dotnet-ef

Tạo Migration

# Tạo migration mới
dotnet ef migrations add <TenMigration> \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API

Áp Dụng Migration

# Áp dụng migrations vào database
dotnet ef database update \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API

Các Lệnh Khác

# Xóa migration cuối (nếu chưa áp dụng)
dotnet ef migrations remove \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API

# Tạo SQL script
dotnet ef migrations script \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API \
  --output migrations.sql

# Liệt kê migrations
dotnet ef migrations list \
  --project src/IamService.Infrastructure \
  --startup-project src/IamService.API

Thiết Lập Neon Database

  1. Tạo database trên Neon Console
  2. Sao chép connection string
  3. Cập nhật appsettings.Development.json:
{
  "ConnectionStrings": {
    "DefaultConnection": "Host=<host>;Port=5432;Database=<db>;Username=<user>;Password=<pass>;SSL Mode=Require"
  }
}
  1. Chạy migrations: dotnet ef database update ...

API Endpoints

Authentication (/api/v1/auth)

Method Endpoint Mô Tả Auth
POST /api/v1/auth/register Đăng ký user mới
POST /connect/token OAuth2 Token (login, refresh)
POST /api/v1/auth/change-password Đổi mật khẩu
POST /api/v1/auth/logout Đăng xuất (revoke tokens)

Email Verification (/api/v1/auth)

Method Endpoint Mô Tả Auth
POST /api/v1/auth/send-verification-email Gửi email xác thực
POST /api/v1/auth/confirm-email Xác nhận email với token

Xác Thực Hai Yếu Tố (/api/v1/auth/2fa)

Method Endpoint Mô Tả Auth
POST /api/v1/auth/2fa/enable Bật 2FA (lấy QR code)
POST /api/v1/auth/2fa/verify Xác minh mã TOTP & kích hoạt
POST /api/v1/auth/2fa/disable Tắt 2FA

Đăng Nhập Mạng Xã Hội (/api/v1/auth)

Method Endpoint Mô Tả Auth
GET /api/v1/auth/external-login/{provider} Bắt đầu 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 providers đã liên kết

User Management (/api/v1/users)

Method Endpoint Mô Tả Auth
GET /api/v1/users Lấy danh sách users (phân trang)
GET /api/v1/users/me Lấy 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 thông tin user
DELETE /api/v1/users/{id} Xóa user (soft delete)

Health Checks

Endpoint Mục Đích
/health Trạng thái health đầy đủ
/health/live Kiểm tra sống
/health/ready Kiểm tra sẵn sàng

Quy Trình Xác Thực

Bước 1: Đăng Ký User Mới

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"
  }'

Response:

{
  "success": true,
  "data": {
    "userId": "550e8400-e29b-41d4-a716-446655440000",
    "email": "user@example.com"
  }
}

Bước 2: Đăng Nhập (Password Grant)

curl -X POST http://localhost:5001/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "client_id=password-client" \
  -d "client_secret=password-client-secret" \
  -d "username=user@example.com" \
  -d "password=Password123!" \
  -d "scope=openid profile email api offline_access"

Response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9...",
  "scope": "openid profile email offline_access"
}

Bước 3: Sử Dụng Access Token

Sử dụng access_token trong header Authorization cho các API được bảo vệ:

curl http://localhost:5001/api/v1/users/me \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."

Bước 4: Làm Mới Token (Khi Access Token Hết Hạn)

curl -X POST http://localhost:5001/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9..."

Bước 5: Đăng Xuất

curl -X POST http://localhost:5001/api/v1/auth/logout \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Client Credentials (Service-to-Service)

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"

Xác Thực Email

Gửi Email Xác Thực

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

Bắt Đầu OAuth Flow

Chuyển hướng user tới:

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 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"}
    ]
  }
}

Swagger UI

Sau khi chạy service, truy cập Swagger UI tại:

Cấu Hình

Biến Môi Trường

Biến Mô Tả Mặc định
ASPNETCORE_ENVIRONMENT Môi trường Development
DATABASE_URL PostgreSQL connection -
JWT_SECRET Secret ký JWT (32+ ký tự) -
REDIS_HOST Redis server host localhost
REDIS_PORT Redis server port 6379
REDIS_PASSWORD Redis password -
REDIS_DATABASE Redis database number 0

Redis Caching

Service sử dụng Redis cho distributed caching thông qua interface ICacheService.

Cấu Hình Redis

Thêm cấu hình Redis trong appsettings.json:

{
  "Redis": {
    "Host": "localhost",
    "Port": 6379,
    "Password": "",
    "Database": 0,
    "ConnectTimeout": 5000,
    "SyncTimeout": 5000
  }
}

Hoặc sử dụng biến môi trường:

REDIS_HOST=your-redis-host
REDIS_PORT=6379
REDIS_PASSWORD=your-password
REDIS_DATABASE=0

ICacheService Interface

public interface ICacheService
{
    // Các thao tác cơ bản
    Task<T?> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan? expiration = null);
    Task RemoveAsync(string key);
    Task<bool> ExistsAsync(string key);
    
    // Get hoặc tạo mới pattern
    Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null);
    
    // Hỗ trợ blacklist token
    Task BlacklistAsync(string key, TimeSpan expiration);
    Task<bool> IsBlacklistedAsync(string key);
}

Ví Dụ Sử Dụng

Get/Set cơ bản:

public class MyService
{
    private readonly ICacheService _cache;
    
    public MyService(ICacheService cache) => _cache = cache;
    
    public async Task<User?> GetUser(string userId)
    {
        return await _cache.GetAsync<User>($"user:{userId}");
    }
    
    public async Task CacheUser(User user)
    {
        await _cache.SetAsync($"user:{user.Id}", user, TimeSpan.FromMinutes(15));
    }
}

Get or Set Pattern (Cache-Aside):

public async Task<User> GetUserById(string userId)
{
    return await _cache.GetOrSetAsync(
        $"user:{userId}",
        async () => await _repository.GetByIdAsync(userId),
        TimeSpan.FromMinutes(15)
    );
}

Blacklist Token (cho Logout):

public async Task Logout(string tokenId)
{
    // Blacklist refresh token trong thời gian còn lại của token
    await _cache.BlacklistAsync($"token:{tokenId}", TimeSpan.FromDays(7));
}

public async Task<bool> IsTokenRevoked(string tokenId)
{
    return await _cache.IsBlacklistedAsync($"token:{tokenId}");
}

Kiểm Thử

dotnet test

Triển Khai

Docker Build

docker build -t goodgo/iam-service:latest .
docker run -p 5001:8080 --env-file .env goodgo/iam-service:latest

Tài Nguyên