首页 > 解决方案 > 为什么可选参数通过而删除参数在策略测试中失败?

问题描述

因此,我为我的应用程序创建了一个测试,该模型是应该可以公开访问Subscription的端点。indexshow

我创建了一个资源控制器来处理来自客户端的 I/O,并创建了一个策略来处理授权,但是在这里,我发现了一些看起来有点奇怪的东西。

在控制器内部,我在构造函数上注册了策略,如下所示:

public function __construct()
{
    $this->middleware('auth:api')->except(['index', 'show']);
    $this->authorizeResource(Subscription::class, 'subscription');
}

然后在策略类中,我修改了默认生成的方法,如下所示:

/**
 * Determine whether the user can view any models.
 *
 * @param  \App\Models\User  $user
 * @return mixed
 */
public function viewAny(?User $user) // <-- notice here I make it optional, the original was required (without "?" mark).
{
    return true; // publicly visible
}

当我运行测试时,它通过了。

public function testSubscriptionIndexArePubliclyAccessible()
{
    $subscriptions = Subscription::factory(10)->create()->toArray();
    $response = $this->get(route('subscriptions.index'));
    $response->assertOk();
    $response->assertExactJson($subscriptions);
}

但是,如果我从方法中完全删除User $user参数,测试将失败。

public function viewAny() <-- if I do this, the test fail. Saying that "this action is unauthorized".
{
    return true; // publicly visible
}

所以..为什么会这样?

标签: laravel

解决方案


在调用策略方法或门功能之前会进行检查。一项检查是是否可以使用用户调用策略方法,canBeCalledWithUser. 这将检查是否有 auth 用户并返回true,如果没有则进行其他检查。下一个检查是该方法是否允许来宾用户,methodAllowsGuests它将使用反射来获取该方法的参数并查看它是否具有类型并且可以为空,但没有参数因此它返回false。因此,您最终不会调用该方法,而是将其视为不存在,这始终是false在授权检查方面。

https://github.com/laravel/framework/blob/8.x/src/Illuminate/Auth/Access/Gate.php#L371 @raw -> callAuthCallback -> resolveAuthCallback

https://github.com/laravel/framework/blob/8.x/src/Illuminate/Auth/Access/Gate.php#L530 @resolveAuthCallback

https://github.com/laravel/framework/blob/8.x/src/Illuminate/Auth/Access/Gate.php#L390 @canBeCalledWithUser

https://github.com/laravel/framework/blob/8.x/src/Illuminate/Auth/Access/Gate.php#L416 @methodAllowsGuests

https://github.com/laravel/framework/blob/8.x/src/Illuminate/Auth/Access/Gate.php#L456 @parameterAllowsGuests - 它没有进入这个方法调用


推荐阅读