laravel authorizeResource 始终拒绝访问

laravel authorizeResource always denies access

我已经为 API 端点创建了一个资源控制器。我也为模型创建了相应的策略。

如果我使用

进行每个方法的授权检查
$this->authorize('delete', $asset);

然后它按预期工作。但是,如果我将以下内容添加到构造中,我总是会收到 403 禁止。不确定我遗漏了什么,因为以下应该对所有方法应用授权。

$this->authorizeResource(Asset::class, 'asset');

这是我的路线:

Route::group(['middleware' => ['auth:api']], function () {
    Route::Resource('asset', 'AssetsApiController');
});

我的保单是这样注册的:

protected $policies = [
    Asset::class => AssetPolicy::class,
];

我的删除政策方法是

public function delete(User $user, Asset $asset)
{
    return true;
}

API 控制器构造函数如下所示:

public function __construct()
{
    $this->authorizeResource(Asset::class,'asset');
}

API控制器方法是

public function destroy($assetID)
{
    $asset = Asset::findOrFail($assetID);
    $asset->delete();
}

我的路线是

| GET|HEAD  | api/asset              | asset.index   | App\Http\Controllers\AssetsApiController@index   | api,auth:api                      |
| POST      | api/asset              | asset.store   | App\Http\Controllers\AssetsApiController@store   | api,auth:api,can:create,App\Asset |
| GET|HEAD  | api/asset/create       | asset.create  | App\Http\Controllers\AssetsApiController@create  | api,auth:api,can:create,App\Asset |
| PUT|PATCH | api/asset/{asset}      | asset.update  | App\Http\Controllers\AssetsApiController@update  | api,auth:api,can:update,asset     |
| DELETE    | api/asset/{asset}      | asset.destroy | App\Http\Controllers\AssetsApiController@destroy | api,auth:api,can:delete,asset     |
| GET|HEAD  | api/asset/{asset}      | asset.show    | App\Http\Controllers\AssetsApiController@show    | api,auth:api,can:view,asset       |
| GET|HEAD  | api/asset/{asset}/edit | asset.edit    | App\Http\Controllers\AssetsApiController@edit    | api,auth:api,can:update,asset     |
| GET|HEAD  | assets                 |               | App\Http\Controllers\AssetsController@index      | web                               |                                               

我想我遗漏了一些东西,但我看不到,Telescope 中的登机口显示为已拒绝。唯一奇怪的是 serveNova 中间件似乎是问题的根源。

Time May 8th 2019, 10:51:37 AM (14m ago)
Hostname core-hosp
Ability delete
Result denied
Location /home/vagrant/code/nova/src/Http/Middleware/ServeNova.php:25
Request View Request
Tags Auth:1

我有同样的问题并通过更改控制器方法的签名解决了它。 默认情况下,控制器接收一个整数 $id 来引用模型,而策略直接接收模型实例。我的直觉是无法在控制器和策略之间进行映射。

所以,我建议尝试将您的控制器方法更改为:

   public function destroy(Asset $asset)
    {
        $asset->delete();
    }

不知道是不是bug?我没有找到关于这些方法类型签名约定的文档。

2021 年 5 月更新

您可以将 $id 保留为默认参数,因为您可以通过在找到相关模型实例之后放置授权调用来允许映射 b/t 控制器和策略,就像这样:

public function destroy($id)
    {   
        $post = Post::find($id);//post instance is created b/4 going through policy.
        $this->authorize('delete',  $post);
        
        $post->delete();
        
        return Post::orderBy('created_at', 'desc')->paginate(3);
    }

我在这里描述了我从这个令人厌烦的问题中吸取的教训:https://github.com/laravel/framework/issues/22847#issuecomment-521308861。也许有人会觉得有用。

我发现为 authorizeResource 获取正确的模型标识符参数非常繁琐。当参数丢失或未正确传递时,Policy 之前的步骤会抛出错误(不是 Policy 本身,因为请求永远不会到达 Policy)。在我的例子中,这意味着我的 CheckUserActive 中间件抛出错误,即使错误出在控制器(而不是中间件)的构造函数中。关于 AuthorizeResource 正在寻找的参数的几点说明:

  1. 必须小写,即使参数声明为大写 您模型中的案例。
  2. 必须是一个字符串(没有很多示例中使用的定义 $ 的变量。)
  3. 必须在单引号内。

例如:

$this->authorizeResource(Model::class, 'parameter');

我通过删除第二个参数解决了这个问题:

    public function __construct()
{
    $this->authorizeResource(Admin::class);
}