【问题标题】:Use multiple Auth guards for one Policy为一个策略使用多个 Auth 防护
【发布时间】:2017-12-31 20:07:04
【问题描述】:

我在 Laravel 5.4 项目中实现了多个 Auth 保护(一个用于管理员,另一个用于普通用户)。到目前为止,这已经成功,管理员和用户都可以登录。我现在正在尝试实现一个适用于两个 Auth 保护的 Policy 类。这是因为我希望所有管理员都可以编辑某些模型,并且只有拥有该模型的用户才能编辑。所以我用这种方法定义了一个策略。

App\Policies\ModelPolicy

public function update(User $user, Model $model)
{
    if ($user->id === $model->user_id) {
        return true;
    }

    if (Auth::guard('admin')->check()) {
        return true;
    }

    return false;
}

然后在我为我的模型使用的任何控制器方法中:

App\Http\Controllers\ModelController

public function update(Model $model)
{
    $this->authorize('update', $model);

    // update model
}

如果普通用户登录,这将非常有效。但是,当管理员用户登录时,它甚至没有达到策略(我从错误日志中知道这一点)。我猜如果Auth::check() 中的默认保护失败,Policy 类会自动拒绝请求。但是,由于我的用户拥有多个守卫之一(不仅仅是默认守卫)是有效的,因此我需要绕过此行为。

我知道我可以在我的控制器方法中实现管理逻辑,并且只有在我知道我正在与非管理员打交道时才使用该策略:

public function update(Model $model)
{
    if (!Auth::guard('admin')->check()) {
        $this->authorize('update', $model);
    }

    // update model
}

但是,如果我的管理条件比简单地登录更复杂,这可能会很快失控。更重要的是,所有这些逻辑都属于策略,不会弄乱我的控制器。

如何为多个身份验证保护使用相同的 Policy 类?

【问题讨论】:

  • 太神奇了,我也有同样的情况:)

标签: laravel laravel-5


【解决方案1】:

我最终覆盖了基本控制器类上的authorize 方法,以使正确的Guard 成为默认Guard。然后,传递给我的策略的 $user 参数将是当前用户登录的任何 Auth 保护的实例。

app/Http/Controllers/Controller.php

use Auth

class Controller extends BaseController
{
    use DispatchesJobs, ValidatesRequests;
    use AuthorizesRequests {
        authorize as protected baseAuthorize;
    }

    public function authorize($ability, $arguments = [])
    {
        if (Auth::guard('admin')->check()) {
            Auth::shouldUse('admin');
        }

        $this->baseAuthorize($ability, $arguments);
    }
}

现在策略将在我的用户模型或管理模型中传递,我需要确保删除参数的类型提示并检查模型的类型是传入的。我不需要做任何Auth::check() 因为我知道传入的$user 必须是我想要的类型的登录用户。

App\Policies\ModelPolicy

use App\User;

public function update($user, Model $model)
{
    if ($user instanceof User) {
        return $user->id == $userId;
    }

    // Is an Admin
    return true;
}

现在我可以访问所需的身份验证保护,在我的策略中使用它做任何我想做的事情。

【讨论】:

  • 这对我有用,非常感谢!不知道为什么这个答案在没有 cmets 的情况下被否决!?
  • $userId 来自哪里?为什么使用 == 而不是 ===?这个答案有很多顾虑。
【解决方案2】:

您可以在通用控制器 (/app/Http/Controllers/Controller.php) 中覆盖“授权”方法:

class Controller extends BaseController
{
    use AuthorizesResources, DispatchesJobs, ValidatesRequests;
    use AuthorizesRequests {
        authorize as protected laravelAuthorize;
    }

    public function authorize($ability, $arguments = [])
    {
        if (!Auth::guard('admin')->check()) {
            $this->laravelAuthorize($ability, $arguments);
        }
    }
}

【讨论】:

  • 嗯,这将通过将逻辑添加到被覆盖的方法来稍微简化控制器代码。问题是这会对该条件进行硬编码。对于与管理员用户相关的每个控制器方法,我都有多个条件(我在示例中只使用了简化版本)。如果我可以达到我的策略,那么自定义逻辑将适用于每种方法 - 问题是 Laravel 阻止我达到策略。我真的很喜欢一个为我提供 Policy 类的自定义和简单性的解决方案。
  • 虽然您的解决方案不是我想要的,但它确实为我指明了覆盖authorize 方法的正确方向。谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-11-14
  • 1970-01-01
  • 2021-11-01
  • 1970-01-01
  • 2021-05-12
  • 2019-01-26
  • 1970-01-01
  • 2023-03-10
相关资源
最近更新 更多