Files
pos-system/services/iam-service-net/docs/vi/README.md

16 KiB

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

Authorization Policies (Phân Quyền API)

Lưu ý: Tất cả API endpoints yêu cầu xác thực (Bearer JWT Token).
Một số endpoints yêu cầu role cụ thể như bảng dưới đây.

Policy Required Role Áp Dụng Cho
RequireSuperAdmin SuperAdmin PAM (Privileged Access Management)
RequireAdmin Admin, SuperAdmin User/Role/Group/Organization management
RequireAuditor Auditor, Admin, SuperAdmin Audit logs, Compliance reports
OwnerOrAdmin Owner hoặc Admin User tự quản lý profile của mình

Chi tiết phân quyền theo Controller:

Controller Policy Mô tả
Users (GET /users, DELETE) RequireAdmin Xem danh sách users, xóa user
Users (GET/PUT /{id}) OwnerOrAdmin User xem/sửa profile mình hoặc Admin
Roles RequireAdmin Quản lý roles
Organizations RequireAdmin Quản lý tổ chức
Groups RequireAdmin Quản lý nhóm
Access Requests RequireAdmin Xử lý yêu cầu truy cập
Access Reviews RequireAdmin Xem xét truy cập định kỳ
Privileged Access RequireSuperAdmin PAM - nhạy cảm nhất
Audit RequireAuditor Xem audit logs
Compliance RequireAuditor Báo cáo tuân thủ
Verifications RequireAdmin Xác thực danh tính

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

Organizations (/api/v1/organizations) - Phase 2

Method Endpoint Mô Tả Auth
GET /api/v1/organizations/{id} Lấy tổ chức theo ID
GET /api/v1/organizations/slug/{slug} Lấy tổ chức theo slug
POST /api/v1/organizations Tạo tổ chức mới
PUT /api/v1/organizations/{id} Cập nhật tổ chức
DELETE /api/v1/organizations/{id} Lưu trữ tổ chức
GET /api/v1/organizations/{id}/hierarchy Lấy phân cấp
GET /api/v1/organizations/{id}/children Lấy tổ chức con

Groups (/api/v1/groups) - Phase 2

Method Endpoint Mô Tả Auth
GET /api/v1/groups Danh sách groups
GET /api/v1/groups/{id} Lấy group theo ID
POST /api/v1/groups Tạo group mới
DELETE /api/v1/groups/{id} Xóa group
POST /api/v1/groups/{id}/members Thêm thành viên
DELETE /api/v1/groups/{id}/members/{userId} Xóa thành viên

Access Requests (/api/v1/access-requests) - Phase 3A

Method Endpoint Mô Tả Auth
POST /api/v1/access-requests Tạo yêu cầu truy cập
GET /api/v1/access-requests Danh sách requests
GET /api/v1/access-requests/{id} Lấy request theo ID
POST /api/v1/access-requests/{id}/submit Submit request
POST /api/v1/access-requests/{id}/approve Phê duyệt
POST /api/v1/access-requests/{id}/reject Từ chối
DELETE /api/v1/access-requests/{id} Hủy request
GET /api/v1/access-requests/pending Requests đang chờ

Access Reviews (/api/v1/access-reviews) - Phase 3B

Method Endpoint Mô Tả Auth
POST /api/v1/access-reviews Tạo access review
GET /api/v1/access-reviews/{id} Lấy review theo ID
POST /api/v1/access-reviews/{id}/items Thêm item
POST /api/v1/access-reviews/{id}/start Bắt đầu review
POST /api/v1/access-reviews/{id}/items/{itemId}/review Certify/Revoke
POST /api/v1/access-reviews/{id}/complete Hoàn thành

Privileged Access (/api/v1/privileged-access) - Phase 3B PAM

Method Endpoint Mô Tả Auth
POST /api/v1/privileged-access/request Yêu cầu JIT access
GET /api/v1/privileged-access/active Grants đang active
POST /api/v1/privileged-access/{id}/revoke Thu hồi access

Audit (/api/v1/audit) - Phase 4A

Method Endpoint Mô Tả Auth
GET /api/v1/audit/logs Lấy audit logs (filtered)

Compliance (/api/v1/compliance) - Phase 4A

Method Endpoint Mô Tả Auth
POST /api/v1/compliance/reports Generate report
GET /api/v1/compliance/reports Danh sách reports
GET /api/v1/compliance/reports/{id} Report chi tiết
POST /api/v1/compliance/reports/{id}/complete Hoàn thành report
GET /api/v1/compliance/violations Violations chưa giải quyết

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