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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:31:10