Skip to content

Can và v-can

Hai cách chặn phần tử giao diện theo quyền. Cả hai đến từ @tasco/nuxt-layer-base: <Can> là component auto-import, v-can là directive do plugin 03.permission đăng ký.

Dùng khi: nút, liên kết hoặc khối nội dung chỉ dành cho người có quyền cụ thể.

Không dùng khi: cả trang cần chặn — khai definePageMeta({ permissions }); hoặc mục menu — khai permission trong NavItem. Xem Chặn theo quyền.

v-can

vue
<!-- Không có quyền → ẩn hẳn -->
<CButton v-can="'/orders/create'" variant="primary">Tạo đơn</CButton>

<!-- Không có quyền → vẫn hiện nhưng khoá -->
<CButton v-can:disable="'/orders/delete'" danger>Xoá</CButton>

<!-- Cần TẤT CẢ các quyền -->
<CButton v-can="['/orders/update', '/orders/approve']">Duyệt</CButton>

v-can:disable gắn thuộc tính disabled, thêm class is-disabled, chặn con trỏ và giảm độ mờ — dùng khi muốn người dùng biết chức năng tồn tại nhưng chưa được cấp quyền.

Chế độ ẩn nhớ lại display ban đầu, nên khi quyền được cấp trong cùng phiên (ví dụ sau khi làm mới session) phần tử hiện lại đúng như cũ.

<Can>

vue
<Can permission="/orders/update">
  <CButton @click="edit">Sửa</CButton>
  <CButton danger @click="remove">Xoá</CButton>
</Can>

<Can :permissions="['/orders/approve', '/orders/reject']" any>
  <CCard title="Phê duyệt">…</CCard>
  <template #fallback>
    <CEmpty description="Bạn không có quyền phê duyệt đơn này." />
  </template>
</Can>
PropKiểuÝ nghĩa
permissionstringMột URI quyền
permissionsstring[]Danh sách quyền; mặc định cần tất cả
anybooleanChỉ cần một quyền bất kỳ trong danh sách

Không khai quyền nào thì nội dung luôn hiện. Slot #fallback hiển thị khi không đủ quyền; bỏ trống thì khối biến mất im lặng.

Chọn cái nào

v-can<Can>
Ẩn / khoáCả haiChỉ ẩn
"Chỉ cần một quyền"KhôngCó (any)
Nội dung thay thếKhôngCó (#fallback)
Phạm viMột phần tửBọc được nhiều phần tử

Trong script thì dùng usePermission():

ts
const { can, canAll, canAny } = usePermission()
if (!can('/orders/delete')) return

Ranh giới

Đây là trải nghiệm, không phải bảo mật

Ẩn nút chỉ làm giao diện gọn. Người dùng vẫn gọi API trực tiếp được — backend phải kiểm tra quyền trên mọi endpoint. Xem Mô hình phân quyền.

Lưu ý

  • Quyền là URI so khớp chính xác: /orders/searchs chỉ đơn giản là không ai có.
  • Khai quyền ở nút thì nhớ khai cả ở trang và ở mục menu — người dùng thấy menu rồi bấm vào gặp 403 là trải nghiệm tệ nhất trong ba khả năng.
  • Đặt URI vào hằng số dùng chung thay vì gõ chuỗi ở từng chỗ.

Liên quan