Laravel 10结合Spatie Permissions实现菜单按角色权限控制
实现基于角色权限的菜单控制方案
1. 给MenuItem模型添加权限关联
要实现按权限控制菜单项访问,首先得让每个MenuItem和Spatie的Permission建立关联,以此指定哪些权限能访问该菜单项。
- 创建中间表迁移文件:
php artisan make:migration create_menu_item_permission_table
在生成的迁移文件中定义表结构:
public function up() { Schema::create('menu_item_permission', function (Blueprint $table) { $table->foreignId('menu_item_id')->constrained()->onDelete('cascade'); $table->foreignId('permission_id')->constrained()->onDelete('cascade'); $table->primary(['menu_item_id', 'permission_id']); }); }
运行迁移:
php artisan migrate
- 修改
MenuItem模型,定义多对多关联(如果你的菜单是嵌套结构,同时定义子项关联):
use Spatie\Permission\Models\Permission; class MenuItem extends Model { // ... 其他已有代码 public function permissions() { return $this->belongsToMany(Permission::class); } public function children() { return $this->hasMany(MenuItem::class, 'parent_id'); } }
2. 扩展菜单查询逻辑,按权限过滤
基于你现有的菜单查询代码,加入权限过滤逻辑,区分超级管理员和普通用户:
use Illuminate\Support\Facades\Auth; class MenuController extends Controller { public function getMenu() { $user = Auth::user(); // 超级管理员直接返回完整菜单 if ($user->hasRole('super-admin')) { $menuItems = MenuItem::whereNull('parent_id') ->with('children.children') // 按需递归加载子项,也可使用嵌套集优化 ->get(); return response()->json($menuItems); } // 普通用户:过滤出有权限访问的菜单项 $userPermissionIds = $user->getAllPermissions()->pluck('id'); // 获取包含用户权限的菜单项,同时处理嵌套子项的权限过滤 $accessibleItems = MenuItem::whereHas('permissions', function ($query) use ($userPermissionIds) { $query->whereIn('permission_id', $userPermissionIds); }) ->orWhereHas('children.permissions', function ($query) use ($userPermissionIds) { // 可选:父项若有可访问的子项,自身也显示(根据业务需求调整) $query->whereIn('permission_id', $userPermissionIds); }) ->with(['children' => function ($query) use ($userPermissionIds) { $query->whereHas('permissions', function ($subQuery) use ($userPermissionIds) { $subQuery->whereIn('permission_id', $userPermissionIds); })->with('children'); }]) ->whereNull('parent_id') ->get(); // 过滤掉无权限且无有效子项的父项 $filteredMenu = $accessibleItems->filter(function ($item) use ($userPermissionIds) { $hasSelfPermission = $item->permissions->pluck('id')->intersect($userPermissionIds)->isNotEmpty(); $hasValidChildren = $item->children->isNotEmpty(); return $hasSelfPermission || $hasValidChildren; }); return response()->json($filteredMenu); } }
3. 权限与菜单的关联管理
超级管理员在后台创建/编辑MenuItem时,可通过表单多选框给菜单项关联对应权限,示例代码如下:
// 给指定MenuItem分配权限 $menuItem = MenuItem::find($menuItemId); $menuItem->permissions()->sync($selectedPermissionIds); // $selectedPermissionIds为权限ID数组
4. 前端适配
Nuxt前端直接接收API返回的过滤后菜单数据,无需额外做权限判断,直接渲染即可。
内容的提问来源于stack exchange,提问作者Ryan H
相关产品推荐
相关产品推荐

