You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:21:01