
本文详解如何在 Laravel + Spatie Laravel-Permission 中高效预加载用户(User)关联的角色(roles)和权限(permissions),解决 with('roles', 'permissions') 无效的问题,并说明团队(team)场景下的关键配置。
本文详解如何在 laravel + spatie laravel-permission 中高效预加载用户(user)关联的角色(roles)和权限(permissions),解决 `with('roles', 'permissions')` 无效的问题,并说明团队(team)场景下的关键配置。
在使用 Spatie Laravel-Permission 扩展包时,开发者常误以为直接调用 with('roles', 'permissions') 即可一次性加载用户的角色与权限。但实际中,permissions 并非 User 模型的原生 Eloquent 关系 —— 它是通过角色间接继承的权限(即“角色所拥有的权限”),User 模型默认不直接拥有 permissions() 关系方法(除非你手动定义了多对多关系)。因此如下代码无法按预期工作:
$user = User::with('roles', 'permissions') // ❌ 错误:User 没有定义 permissions 关系
->when(request()->q, fn($q) => $q->where('name', 'like', '%'.request()->q.'%'))
->latest()
->paginate(20);✅ 正确做法是:利用 Spatie 提供的 load() 或 with() 预加载 roles,再通过 roles.permissions 实现嵌套预加载(即“角色及其权限”)。这是标准且高效的方式:
$user = User::with('roles.permissions') // ✅ 正确:预加载角色 + 每个角色的权限
->when(request()->q, fn($query) => $query->where('name', 'like', '%'.request()->q.'%'))
->latest()
->paginate(20);此时,每个 $user->roles 集合中的 Role 实例均携带其关联的 permissions,你可安全访问:
@foreach ($user->roles as $role)
<div>角色:{{ $role->name }}</div>
<ul>
@foreach ($role->permissions as $permission)
<li>{{ $permission->name }}</li>
@endforeach
</ul>
@endforeach⚠️ 特别注意:若你启用了 多团队(teams)支持(即 teams => true),必须在查询前显式设置当前团队 ID,否则权限/角色查询将因 team_id 约束失效而返回空结果:
Route::get('/user-infos', function () {
\Spatie\Permission\PermissionRegistrar::setPermissionsTeamId(1); // ✅ 必须提前设置
$users = User::with('roles.permissions')
->latest()
->get();
return response()->json($users);
});? 补充说明:
- setPermissionsTeamId() 是 Spatie v5+ 推荐方式(旧版用 setTeamId());
- 若使用团队功能,所有涉及权限/角色的 Eloquent 查询前都需调用该方法(建议在中间件或服务提供者中统一处理);
- 不要尝试为 User 模型手动添加 permissions() 关系(如 belongsToMany(Permission::class)),这会绕过 Spatie 的权限继承逻辑(如角色赋予的权限),导致数据不一致。
✅ 总结最佳实践:
- 使用 with('roles.permissions') 预加载,而非 'roles', 'permissions';
- 多团队项目务必在查询前调用 \Spatie\Permission\PermissionRegistrar::setPermissionsTeamId($teamId);
- 如需获取用户直接分配的权限(非通过角色继承),可启用 user_has_permissions 表并配置 User 模型的 permissions() 关系(需在 HasRoles trait 外手动定义,且仅适用于明确需要直接赋权的场景)。


















