6.7 KiB
6.7 KiB
name, description
| name | description |
|---|---|
| 權限管理與實作規範 | 為新功能實作權限控制的完整流程規範,包含後端 Seeder 設定、Middleware 路由保護與前端權限判斷。 |
權限管理與實作規範
本文件說明如何在新增功能時,一併實作完整的權限控制機制。專案採用 spatie/laravel-permission 套件進行權限管理。
1. 定義權限 (Backend Seeder)
所有權限皆定義於 database/seeders/PermissionSeeder.php。
步驟:
- 開啟
database/seeders/PermissionSeeder.php。 - 在
$permissions關聯陣列中新增功能對應的權限。- 命名慣例:
{resource}.{action}(例如:system.view_logs,products.create) - 格式:
'權限字串' => '中文動作名稱' - 常用動作:
view,create,edit,delete,approve,cancel,export
- 命名慣例:
- 在下方「角色分配」區段,將新權限分配給適合的角色。
範例:
// 1. 新增權限(注意:是 key => value 格式)
$permissions = [
// ... 現有權限
'utility_fees.view' => '檢視',
'utility_fees.create' => '建立',
'utility_fees.edit' => '編輯',
'utility_fees.delete' => '刪除',
];
// 2. 分配給角色
$admin->givePermissionTo([
// ... 現有權限
'utility_fees.view', 'utility_fees.create', 'utility_fees.edit', 'utility_fees.delete',
]);
現有角色定義:
| 角色 | 說明 | 權限範圍 |
|---|---|---|
super-admin |
系統管理員 | 自動擁有所有權限(Permission::all()) |
admin |
一般管理員 | 大部分權限(除角色管理外) |
warehouse-manager |
倉庫管理員 | 庫存、盤點、調撥、進貨、門市叫貨 |
purchaser |
採購人員 | 商品檢視、採購單、退貨、供應商、進貨 |
viewer |
檢視人員 | 僅限各模組的 .view 權限 |
2. 套用資料庫變更 (Multi-tenancy)
修改 Seeder 後,必須在中央與所有租戶同步執行。
# 對所有租戶執行 Seeder
./vendor/bin/sail php artisan tenants:seed --class=PermissionSeeder
Warning
僅執行
db:seed只會更新中央資料庫。務必使用tenants:seed確保所有租戶同步。
3. 路由保護 (Backend Middleware)
路由保護定義在各模組自己的 app/Modules/{ModuleName}/Routes/web.php 中。
Important
路由檔在各模組內(如
app/Modules/Finance/Routes/web.php),不是全域的routes/web.php。
範例:
// 單一權限保護
Route::middleware('permission:utility_fees.view')->group(function () {
Route::get('/utility-fees', [UtilityFeeController::class, 'index'])->name('utility-fees.index');
Route::get('/utility-fees/{utilityFee}', [UtilityFeeController::class, 'show'])->name('utility-fees.show');
});
// 巢狀權限群組
Route::middleware('permission:utility_fees.create')->group(function () {
Route::get('/utility-fees/create', [UtilityFeeController::class, 'create'])->name('utility-fees.create');
Route::post('/utility-fees', [UtilityFeeController::class, 'store'])->name('utility-fees.store');
});
// 單行 middleware
Route::delete('/utility-fees/{utilityFee}', [UtilityFeeController::class, 'destroy'])
->middleware('permission:utility_fees.delete')
->name('utility-fees.destroy');
4. 配置權限群組名稱 (Backend UI Config)
為了讓新權限在「角色與權限」管理介面中正確分組並顯示中文標題,需修改 Controller。
位置: app/Modules/Core/Controllers/RoleController.php → getGroupedPermissions()
$groupDefinitions = [
'products' => '商品資料管理',
'warehouses' => '倉庫管理',
'inventory' => '庫存資料管理',
// ...
'utility_fees' => '公共事業費管理', // ✅ 新增此行
];
Note
未加入
$groupDefinitions的權限群組仍會顯示,但標題會以原始 key(英文)呈現。
5. 前端權限判斷 (React)
5.1 方式一:usePermission Hook(在邏輯中判斷)
位置: resources/js/hooks/usePermission.ts
import { usePermission } from "@/hooks/usePermission";
export default function ProductIndex() {
const { can, canAny, isSuperAdmin } = usePermission();
return (
<div>
{can('products.create') && <Button>新增商品</Button>}
{canAny(['products.edit', 'products.delete']) && <ManageDropdown />}
</div>
);
}
Hook 完整介面:
| 方法 | 說明 |
|---|---|
can(permission) |
檢查是否擁有指定權限 |
canAny(permissions[]) |
檢查是否擁有任一權限 |
canAll(permissions[]) |
檢查是否擁有所有權限 |
hasRole(role) |
檢查是否擁有指定角色 |
hasAnyRole(roles[]) |
檢查是否擁有任一角色 |
hasAllRoles(roles[]) |
檢查是否擁有所有角色 |
isSuperAdmin() |
是否為超級管理員 |
所有方法對
super-admin角色自動回傳true。
5.2 方式二:<Can> / <HasRole> / <CanAll> 元件(在 JSX 中包裹)
位置: resources/js/Components/Permission/Can.tsx
import { Can, HasRole, CanAll } from '@/Components/Permission/Can';
// 單一權限
<Can permission="products.create">
<Button>新增商品</Button>
</Can>
// 任一權限(OR 邏輯)
<Can permission={['products.edit', 'products.delete']}>
<ManageDropdown />
</Can>
// 所有權限都必須有(AND 邏輯)
<CanAll permissions={['products.edit', 'products.delete']}>
<Button>完整管理</Button>
</CanAll>
// 角色判斷
<HasRole role="admin">
<Link href="/admin">管理後台</Link>
</HasRole>
// Fallback 支援
<Can permission="products.delete" fallback={<span className="text-gray-400">無權限</span>}>
<Button variant="destructive">刪除</Button>
</Can>
Important
UI 規範要求:所有可操作按鈕(新增、編輯、刪除)必須包裹
<Can>元件或使用can()判斷。 詳見 UI 統一規範。
6. 開發檢核清單 (Checklist)
後端
PermissionSeeder.php已新增權限字串('key' => '中文動作名稱'格式)。PermissionSeeder.php已將新權限分配給admin及其他適用角色。- 已執行
./vendor/bin/sail php artisan tenants:seed --class=PermissionSeeder同步所有租戶。 RoleController.php的$groupDefinitions已新增權限群組中文名稱。- 模組路由 (
app/Modules/{ModuleName}/Routes/web.php) 已加上middleware('permission:...')保護。
前端
- 頁面按鈕已使用
usePermissionHook 或<Can>元件進行權限控制。 - 所有可操作按鈕都包裹於權限判斷中(符合 UI 統一規範)。