Xác thực (Authentication) cho một ứng dụng rât dễ. Nhưng xác thực cho 3 ứng dụng với 3 loại user khác nhau trên cùng một Database là bài toán khó.
1. Database Schema (Prisma)
Chúng ta cần thiết kế bảng User linh hoạt để hỗ trợ nhiều vai trò.
model User {
id String @id @default(cuid())
email String @unique
password String // Hashed
role UserRole @default(CUSTOMER)
// Relations
merchantId String? // Nếu là MERCHANT STAFF
orders Order[]
}
enum UserRole {
SUPER_ADMIN
MERCHANT_OWNER
MERCHANT_STAFF
CUSTOMER
}
model Merchant {
id String @id @default(cuid())
name String
users User[] // Nhân viên của Merchant này
}2. Authentication Flow
Sử dụng NextAuth.js v5 với Strategy chia sẻ cookie hoặc JWT.
Kịch bản 1: Login riêng biệt
admin.app.com/login-> Chỉ cho phépSUPER_ADMIN.merchant.app.com/login-> Chỉ cho phépMERCHANT_OWNERvàMERCHANT_STAFF.store.app.com/login-> Chỉ cho phépCUSTOMER.
Code Logic (Middleware Protection)
Tại mỗi ứng dụng, chúng ta dùng Middleware để chặn sai Role.
// apps/admin/middleware.ts
import { auth } from "@/auth"
export default auth((req) => {
const userRole = req.auth?.user?.role;
if (userRole !== 'SUPER_ADMIN') {
return Response.redirect(new URL('/unauthorized', req.url))
}
})3. Session Management
Nếu bạn muốn trải nghiệm Single Sign-On (SSO) - Đăng nhập 1 lần vào được tất cả:
- Cần đặt các app dưới sub-domain:
store.domain.com,admin.domain.com. - Cấu hình Cookie Domain là
.domain.com.
Tuy nhiên, trong dự án này, để bảo mật cao nhất, chúng ta giữ Session riêng biệt (Isolated Sessions). Admin đăng nhập Admin Portal không có nghĩa là tự động đăng nhập vào Storefront với tư cách Customer (trừ khi có tính năng Impersonate).
4. Bảo mật API (Shared API)
Nếu chúng ta dùng chung một Backend (Monolith API) hoặc Server Actions trong Monorepo:
// packages/actions/product.ts
export async function createProduct(data: ProductInput) {
const session = await getSession();
// Security Gate
if (session.role !== 'MERCHANT_OWNER') {
throw new Error("Forbidden");
}
// Logic tạo sản phẩm...
}Việc đặt logic check quyền ngay trong Server Action (được share từ thư mục packages) giúp logic bảo mật nhất quán dù được gọi từ UI nào.