服务提供商期间未调用授权门

Authorization gate not called during service provider

我在 AuthServiceProvider 中定义了一个 admin 门,用于向某些模型添加全局查询范围。假设我有模型 A,由 Observer(在 AppServiceProvider 中注册)观察,以及 B,利用 admin 门添加全局查询范围。

// app/Providers/AuthServiceProvider.php
class AuthServiceProvider extends ServiceProvider
{
  public function boot()
  {
    Gate::define('admin', [static::class, 'admin']);
  }

  public static function admin(User $user): bool
  {
    return $user->group->name === 'Admin';
  }
}
// app/B.php
class B extends Eloquent
{
  public static function boot()
  {
    parent::boot();

    if (!Gate::allows('admin')) {
      static::addGlobalScope('public', function ($query) {
        $query->where('public', true);
      });
    }
  }
}

到目前为止一切正常。然后我添加了一个模型 C,它有一个 Observer 并使用 admin 门。由于 C::observe() 触发 C::boot() 并且 AppServiceProviderAuthServiceProvider 之前注册,门未定义,我将 Observer 注册提取到新的 ObserverServiceProviderAuthServiceProvider.

之后注册
// app/C.php
class C extends Eloquent
{
  public static function boot()
  {
    parent::boot();

    if (!Gate::allows('admin')) {
      static::addGlobalScope('public', function ($query) {
        $query->where('public', true);
      });
    }
  }
}
// app/Providers/ObserverServiceProvider.php
class ObserverServiceProvider extends ServiceProvider
{
  public function boot()
  {
    A::observe(AObserver::class);
    C::observe(CObserver::class);
  }
}
// config/app.php
'providers' => [
  //...
  App\Providers\AppServiceProvider::class,
  App\Providers\AuthServiceProvider::class,
  //...
  App\Providers\ObserverServiceProvider::class,
]

我的问题:

AC 的观察者以及 Bboot() 方法中的 admin 门仍在工作,但是 Gate::allows('admin') in C 始终 returns false 甚至不调用门函数。

C::boot() 中添加一个 var_dump(Gate::has('admin')) 输出 true 并稍后在同一请求中的 View 中使用 @can('admin') 也可以正常工作,因此门已明确定义并在原则上工作。

无法调用授权门,因为会话数据(以及经过身份验证的用户)由 StartSession 中间件提供,该中间件在服务提供商之后运行。

问题可以通过将Gate::allows()检查放在匿名函数中来解决,因此它只在构建查询时执行:

// app/C.php
class C extends Eloquent
{
  public static function boot()
  {
    parent::boot();

    static::addGlobalScope('public', function ($query) {
      if (!Gate::allows('admin')) {
        $query->where('public', true);
      }
    });
  }
}