基于Spatie/Laravel实现用户分门店(Sub_Location)权限管控咨询
基于Spatie Laravel权限实现门店维度的角色/权限管控
1. 扩展用户模型与关联关系
在User模型中添加与User_Locations的关联,用于获取用户和门店的绑定记录:
// app/Models/User.php public function userLocations() { return $this->hasMany(UserLocation::class, 'user_id'); } // 获取用户在指定门店的有效绑定记录 public function getValidUserLocation($subLocationId) { return $this->userLocations() ->where('sub_location_id', $subLocationId) ->where('status', 'Y') ->first(); }
2. 新增门店维度的角色/权限校验方法
在User模型中添加针对门店的角色和权限校验逻辑,适配现有表结构:
角色校验方法
// 检查用户在指定门店是否拥有目标角色 public function hasRoleInSubLocation($role, $subLocationId) { $userLocation = $this->getValidUserLocation($subLocationId); if (!$userLocation) return false; // 先给User_Locations表新增role_id字段(关联Spatie的roles表) $roleId = is_numeric($role) ? $role : \Spatie\Permission\Models\Role::where('name', $role)->value('id'); return $userLocation->role_id == $roleId; }
权限校验方法
// 检查用户在指定门店是否拥有目标权限 public function canInSubLocation($permission, $subLocationId) { $userLocation = $this->getValidUserLocation($subLocationId); if (!$userLocation) return false; // 通过门店绑定的角色获取权限 $role = \Spatie\Permission\Models\Role::find($userLocation->role_id); return $role ? $role->hasPermissionTo($permission) : false; }
3. 管理当前门店上下文
用户登录后需选择门店,将选中的sub_location_id存入Session,实现全局校验的上下文统一:
门店选择控制器示例
// app/Http/Controllers/SubLocationController.php public function select(Request $request, $subLocationId) { if (!auth()->user()->getValidUserLocation($subLocationId)) { abort(403, '无权限访问该门店'); } session(['current_sub_location' => $subLocationId]); return redirect()->route('dashboard'); }
中间件强制门店选择
创建EnsureSubLocationSelected中间件,确保用户操作前已选定门店:
// app/Http/Middleware/EnsureSubLocationSelected.php public function handle(Request $request, Closure $next) { if (!session()->has('current_sub_location')) { return redirect()->route('sub-location.select'); } return $next($request); }
将中间件注册到路由组,管控需要门店权限的页面:
// routes/web.php Route::middleware(['auth', 'ensure.sub.location'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard'); Route::put('/content/{id}', [ContentController::class, 'update'])->name('content.update'); });
4. 控制器中的权限校验
结合Session中的当前门店ID,在控制器内做权限拦截:
// app/Http/Controllers/ContentController.php public function update(Request $request, $id) { $currentSubLocation = session('current_sub_location'); if (!auth()->user()->canInSubLocation('edit-content', $currentSubLocation)) { abort(403, '无权限在当前门店编辑内容'); } // 执行内容更新逻辑 // ... }
5. 视图中的权限控制
在Blade视图中通过自定义方法控制元素显示:
@if(auth()->user()->canInSubLocation('edit-content', session('current_sub_location'))) <a href="{{ route('content.edit', $content->id) }}" class="btn btn-primary">编辑内容</a> @endif @if(auth()->user()->hasRoleInSubLocation('admin', session('current_sub_location'))) <div class="admin-panel"> <!-- 管理员专属操作区域 --> </div> @endif
可选:扩展Spatie Gate简化校验
若想直接使用Spatie默认的@can指令,可在AuthServiceProvider中扩展Gate逻辑:
// app/Providers/AuthServiceProvider.php public function boot() { $this->registerPolicies(); Gate::before(function ($user, $ability) { $currentSubLocation = session('current_sub_location'); if ($currentSubLocation) { return $user->canInSubLocation($ability, $currentSubLocation) ?: null; } return null; }); }
之后视图中可直接使用默认指令:
@can('edit-content') <a href="{{ route('content.edit', $content->id) }}" class="btn btn-primary">编辑内容</a> @endcan
内容的提问来源于stack exchange,提问作者Lokesh M
相关产品推荐
相关产品推荐

