Bài 14 · Nâng cao · 26 phút
Trang quản trị & phân quyền Casbin
Biên soạn bởi Nguyễn Anh Tuấn
Dựng trang quản trị (admin dashboard) cho web bán hàng: quản lý tài khoản, hàng & kho, giao dịch nạp tiền và số dư khách. Tách quyền rạch ròi giữa khách thường (trang mua hàng) và admin bằng Casbin: vai trò (role), chính sách (policy) và vì sao authorization (được làm gì) khác authentication (bạn là ai). Subagent bảo mật rà soát để admin không lọt ra ngoài.
Khách đã mua hàng được rồi, nhưng mèo con cần một nơi của riêng mình để quản lý cửa hàng: thêm/sửa sản phẩm, theo dõi kho, xem giao dịch nạp tiền và số dư khách. Đó là trang quản trị (admin dashboard) - tách khỏi trang mua hàng của khách.
Dựng giao diện admin thì dễ. Việc khó và quan trọng là: làm sao chỉ mèo con (admin) vào được, khách thường thì không.
Hai khái niệm dễ lẫn. Authentication (xác thực) là "bạn là ai" - phần Better-auth đã lo. Authorization (phân quyền) là "bạn được làm gì". Một khách đã đăng nhập (qua authn) vẫn không được vào trang quản trị (chặn ở authz).
- ▸Authentication: bạn là ai (đăng nhập) - đã có ở bài Better-auth.
- ▸Authorization: bạn được làm gì - bài này lo.
- ▸Đăng nhập KHÔNG có nghĩa được làm mọi thứ; admin là một lớp quyền riêng.
Khoá dùng Casbin để phân quyền. Mèo con khai báo vai trò (role) - vd "khach" và "admin" - và chính sách (policy) - luật "vai trò nào được làm gì". Mỗi request tới khu admin, Casbin trả lời cho phép hay từ chối:
Policy Casbin - mã giả minh hoạ (ai, làm gì, trên đâu)
# vai trò admin được mọi hành động trong khu /admin
admin, /admin/*, *
# vai trò khach chỉ được xem trang mua hàng
khach, /san-pham, xem
# gán vai trò cho tài khoản
meo_chu_shop -> admin
khach_le -> khach Một cạm bẫy chết người: chỉ ẩn nút admin trên giao diện. Ẩn nút mới là cho gọn mắt; khách thường vẫn có thể gõ thẳng địa chỉ /admin hoặc gọi API. Nếu server không chặn, dữ liệu lọt hết.
Trung thực
Mô tả cho Claude khá gọn: dựng khu /admin quản lý tài khoản, hàng, kho, giao dịch và số dư; gắn Casbin với vai trò khach/admin; và chặn mọi route admin bằng kiểm quyền trước khi chạy. Claude lo phần dựng; mèo con kiểm lại đúng ý đồ.
- ▸Admin quản: tài khoản, sản phẩm & kho, giao dịch nạp tiền, số dư khách.
- ▸Casbin gác cửa: gán vai trò cho tài khoản, policy quyết định quyền.
- ▸Chặn ở server cho TỪNG route admin - không dựa vào việc ẩn nút.
Admin dashboard chủ yếu là bảng (table) và biểu mẫu (form): danh sách đơn, kho, giao dịch nạp tiền. Dựng nó bằng cùng design system - primary color + bảng màu + shadcn-react/Tailwind đã thiết lập ở bài Skills & Subagents - để admin và trang khách trông như một sản phẩm, không lệch màu mỗi nơi một kiểu.
- ▸Dùng lại design tokens (primary + bảng màu) → admin nhất quán với shop.
- ▸Bảng & form dựng bằng shadcn-react + Tailwind; layout admin thường là sidebar + vùng nội dung.
- ▸Mobile-first: nhiều người quản cửa hàng bằng điện thoại - bảng phải cuộn ngang hoặc xếp lại, nút đủ to.
Mẹo
Admin quản vận hành - hàng, đơn, số dư - nhưng không có quyền chạm vào tài khoản của khách hay user cấp dưới: không đọc hay đặt mật khẩu hộ, không tắt hay reset 2FA của họ. Quản trị không phải là chiếm tài khoản.
- ▸Mật khẩu đã băm một chiều - admin cũng KHÔNG đọc được (như bài đăng nhập).
- ▸2FA (Passkey/TOTP) do CHÍNH CHỦ tài khoản quản; admin không tắt/reset hộ.
- ▸Admin cùng lắm tạm khoá (suspend) tài khoản vi phạm, không mạo danh đăng nhập.
- ▸Mọi thao tác admin lên tài khoản người khác đều ghi log để truy vết.
Trung thực
Sản phẩm lớn lên thường có thêm manager - được admin cấp một phần quyền, trong đó có quyền phân quyền cho user khác. Đây là chỗ dễ bị leo thang phân quyền (privilege escalation): manager tự nâng quyền mình, hoặc cấp cho user khác quyền cao hơn quyền manager đang có.
- ▸Không ai cấp được quyền mình KHÔNG có: chỉ gán được tập quyền là con của quyền mình.
- ▸Không tự sửa vai trò/quyền của CHÍNH MÌNH lên cao hơn.
- ▸Vai trò có thứ bậc: manager dưới admin; manager không sửa được admin hay user ngang/cao hơn.
- ▸Mọi thay đổi phân quyền kiểm ở SERVER (Casbin) và ghi log (audit) để truy vết.
Trung thực
Phân quyền sai là một trong những lỗ hổng hay gặp nhất (và nguy hiểm nhất). Trước khi mở, cho subagent bảo mật (OWASP) rà phần phân quyền, và tự thử: đăng nhập bằng tài khoản khách rồi gọi thẳng URL admin xem có lọt không.
Bước tiếp theo
Câu hỏi thường gặp
Authentication (xác thực) trả lời "bạn là ai" - phần Better-auth lo ở bài đăng nhập. Authorization (phân quyền) trả lời "bạn được làm gì" - một khách đã đăng nhập vẫn KHÔNG được vào trang quản trị. Bài này lo phần thứ hai.
Casbin là một thư viện phân quyền: mèo con khai báo VAI TRÒ (role) và CHÍNH SÁCH (policy) - ai, được làm gì, trên cái gì - rồi Casbin trả lời "cho phép" hay "từ chối" cho từng request. Khoá dùng nó để tách rạch ròi khách thường và admin.
Role (vai trò) là nhóm quyền, vd "khach" và "admin". Policy (chính sách) là luật "vai trò X được làm hành động Y trên tài nguyên Z", vd "admin được xem và sửa mọi đơn hàng". Gán vai trò cho tài khoản, rồi policy quyết định họ làm được gì.
Không. Ẩn nút chỉ là cho gọn mắt (UX). Khách thường vẫn có thể gọi thẳng URL hay API của admin. Phải KIỂM QUYỀN Ở SERVER cho mọi route admin - ẩn nút mà không chặn ở backend là cửa mở toang.
Có. Admin nhiều bảng và biểu mẫu, lại hay được dùng trên điện thoại khi chủ shop đi ngoài, nên cần mobile-first (bảng cuộn ngang hoặc xếp lại, nút đủ to). Dựng bằng cùng design system (primary color + bảng màu + shadcn-react/Tailwind) như trang khách để hai phần nhất quán, rồi cho subagent rà giao diện kiểm responsive.
Không. Admin quản vận hành (hàng, đơn, số dư) chứ không chạm vào tài khoản người khác: mật khẩu đã băm nên admin cũng không đọc được, còn 2FA (Passkey/TOTP) do chính chủ tài khoản quản. Cho admin đặt lại mật khẩu/2FA hộ là mở cửa cho nội gián chiếm tài khoản. Khách mất 2FA thì dùng luồng tự phục hồi (backup codes/xác minh), không phải admin bấm nút.
Là khi một người (vd manager được cấp quyền phân quyền) tự nâng quyền mình, hoặc cấp cho user khác quyền CAO HƠN quyền mình đang có. Chặn bằng nguyên tắc: chỉ gán được tập quyền là con của quyền mình, không tự sửa vai trò mình lên cao hơn, và mọi thay đổi phân quyền đều kiểm ở server (Casbin) + ghi log.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Authorization (phân quyền) trả lời câu hỏi gì?
- 1
Dựng trang admin cơ bản
Nhờ Claude tạo trang /admin hiển thị danh sách tài khoản và sản phẩm (đọc từ database).
✅ Hoàn thành khi: Khi đăng nhập bằng tài khoản admin, vào /admin thấy danh sách tài khoản và sản phẩm.
- 2
Khai báo vai trò & policy Casbin
Nhờ Claude gắn Casbin với hai vai trò "khach" và "admin", và policy cho admin được vào khu /admin.
✅ Hoàn thành khi: Có cấu hình Casbin với hai vai trò và ít nhất một policy cho admin; Claude giải thích được luật.
- 3
Chặn route admin ở server
Nhờ Claude bắt mọi route trong /admin kiểm quyền (qua Casbin) TRƯỚC khi chạy.
✅ Hoàn thành khi: Tài khoản khách gọi /admin bị chặn (403) và không thấy dữ liệu nào.
- 4
Thử lọt quyền
Đăng nhập bằng tài khoản khách rồi gọi thẳng URL hoặc API của admin (không qua nút).
✅ Hoàn thành khi: Bị từ chối ở server - xác nhận việc chặn nằm ở backend chứ không chỉ là ẩn nút trên giao diện.
- 5
Cấp quyền admin cho một tài khoản
Gán vai trò admin cho một tài khoản, rồi kiểm tài khoản đó vào /admin được, còn tài khoản thường thì không.
✅ Hoàn thành khi: Tài khoản được gán admin vào /admin được; tài khoản thường vẫn bị chặn.
- 6
Giao diện admin theo design system
Nhờ Claude dựng giao diện /admin (sidebar + bảng đơn/kho/giao dịch) dùng đúng design tokens đã chọn, và yêu cầu mobile-first; cho subagent rà giao diện kiểm responsive.
✅ Hoàn thành khi: Trang /admin dùng đúng primary color/bảng màu như shop và hiển thị gọn trên màn hình điện thoại (bảng không vỡ layout).
- 7
Khoá ranh giới của admin
Nhờ Claude đảm bảo không có route/đường nào để admin đọc/đặt mật khẩu hay reset 2FA của user khác; thử bằng tài khoản admin.
✅ Hoàn thành khi: Admin KHÔNG đổi được mật khẩu/2FA của user khác; mọi thao tác admin lên tài khoản người khác đều ghi log.
- 8
Thử leo thang phân quyền
Tạo một manager với quyền hạn chế (có quyền phân quyền); thử để manager tự nâng quyền mình hoặc cấp cho user quyền cao hơn manager.
✅ Hoàn thành khi: Server (Casbin) chặn các thử nghiệm đó; manager chỉ cấp được quyền là con của quyền mình; có log lại.
- 9
Cho subagent bảo mật rà
Gọi subagent rà bảo mật (OWASP) kiểm phần phân quyền và các route admin.
✅ Hoàn thành khi: Có danh sách phát hiện; mỗi mục được sửa hoặc mèo con xác nhận lý do an toàn.