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

Laravel 11:使用Gates和Policies限制用户访问Sites资源

解决Laravel 11中限制用户仅查看自身Site资源的问题

问题分析

你的代码存在几个关键问题:

  • AppServiceProvider中的guessPolicyNamesUsing闭包为空,导致Laravel无法正确关联Site模型和SitePolicy
  • 路由的can中间件传递的是字符串'site',而非实际的Site实例,策略无法获取到要检查的资源
  • SitePolicy的view方法没有实现实际的权限判断逻辑
  • 路由的控制器写法不符合Laravel 11的规范(应指定控制器类和方法)

解决方案

1. 修复策略与模型的关联

Laravel默认会按照「模型名+Policy」的约定自动关联模型和策略,直接删除AppServiceProvider中guessPolicyNamesUsing的空闭包即可:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider { 
    public function register(): void {  }

    public function boot(): void  {   
        // 移除空的guessPolicyNamesUsing,依赖框架默认约定
    }
}

如果需要自定义策略命名规则,需在闭包中返回正确的策略类名:

use Illuminate\Support\Facades\Gate;

Gate::guessPolicyNamesUsing(function (string $modelClass) {
    return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
});

2. 修正路由配置

使用模型绑定让Laravel自动根据id获取Site实例,同时在can中间件中传递该实例:

use App\Http\Controllers\SiteController;
use App\Models\Site;

Route::get('/view/{site}', [SiteController::class, 'view'])
    ->name('sites.view')
    ->can('view', 'site'); // 这里的'site'对应路由参数{site}的名称

若无法使用模型绑定,也可通过闭包传递实例:

Route::get('/view/{id}', [SiteController::class, 'view'])
    ->name('sites.view')
    ->can('view', function ($id) {
        return \App\Models\Site::findOrFail($id);
    });

3. 完善SitePolicy的权限判断逻辑

假设Site模型通过user_id字段关联用户,修改view方法判断当前用户是否为站点所有者:

namespace App\Policies;

use App\Models\Site;
use App\Models\User;

class SitePolicy {
    public function view(User $user, Site $site): bool {
        // 验证用户ID与站点的user_id匹配
        return $user->id === $site->user_id;
    } 
}

如果是多对多关联(用户与站点通过中间表绑定),可改为:

public function view(User $user, Site $site): bool {
    return $user->sites()->where('site_id', $site->id)->exists();
}

4. 调整控制器方法接收Site实例

在SiteController的view方法中直接接收经过权限验证的Site实例:

namespace App\Http\Controllers;

use App\Models\Site;

class SiteController extends Controller {
    public function view(Site $site) {
        // 直接使用已验证的$site数据返回视图或响应
        return view('sites.view', compact('site'));
    }
}

测试验证

访问/view/{site_id}时,非站点所有者会收到403禁止访问响应,所有者则可正常查看站点内容。

内容的提问来源于stack exchange,提问作者Dev Newbie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:52:37