关于Laravel策略方法的参数问题



我的控制器方法:

public function store(StoreTradeRequest $request, StoreTradeService $service)
{
$this->authorize('store', [Trade::class, $request->all()]);
// ...
}

我的政策:

public function store(User $user, array $request): Response|bool
{
return $user->id == $request['trader_id'];
}

我的代码工作,但我有一个问题与授权方法的第二个参数在控制器。如您所见,它是一个包含两个项的数组,而我只需要策略端的请求。我不明白为什么,但如果我只发送请求,我得到以下错误:

Too few arguments, 1 passed, 2 expected.

我和"Trade::class,"它不能达到政策方法,但不知何故,我需要它在那里使它起作用。知道这是怎么回事吗?

我用我能想到的所有形式传递$request,结果都是一样的。

'store', $request
'store', [$request]
'store', $request->all()
'store', $request->validated()
'store', [$request->all()]
'store', [$request->validated()]

General

当你试图通过不使用模型来使用policy时,你应该以另一种方式使用/register,因为正如我所说,它意味着与模型一起使用,在这种情况下,你不使用它,应用程序希望你以某种方式传递或注入它。

这是注册策略的常规方式,您应该将您的策略添加到protected $policies,这是您所说的方式。

Laravel用同样的方法来发现你的策略,就像我解释的那样。

对注释和关闭此的回答

I think your answer has some good points and lots of unnecessary addition to the codebase which may helpful as an answer to a different question

下面的信息是必须知道的,我将保留在这里,因为有好的方法和坏的方法来做事情,但另一方面,你有只传递请求的问题,你用更好的方法得到了解决方案,原因是类名等的目的(干净的代码&固体)。

  • 第一种方法是使用GATE完成此操作的方法,但这可能使用更多行,另一方面,它可以在执行路由(和刀片和…)时有用,因为在大多数情况下你有来自route等的参数。
  • 第二种方法更准确,但它基本上是一个技巧,让一个常见的东西来处理更多的场景,因为有一个特定的目的,政策和范围可以做什么来授权。
  • 正如我所说的,它意味着与模型一起使用,但第二种方法可能被用作api,当然,当你传递参数时,你只会传递所需的东西,而不是其他东西来混淆那些试图阅读你的代码的人,在这种情况下,你正在传递Trade,但在策略中,你从未使用过它。

基本例子:

public function store(StoreTradeRequest $request, StoreTradeService $service)
{
$this->authorize('store', [Trade::class, $request->all()]);
// Change above line to below
$this->authorize('store', $request->all());
// ...
}

像下面这样使用HandlesAuthorizationTrait:

use HandlesAuthorization;
// rest of the code look fine base on what you have in your mine.
public function store(User $user, array $request): bool
{
return true;
}
// If user is guest, you can check for user too like below
// ?User $user
public function store(?User $user, array $request): bool

如果您试图通过访问与用户相关的实际数据来验证您的数据,强烈建议您尝试其他方法,因为策略意味着规定对模型的访问。

编辑01:Base onI didn't register it. My policy and model name are the same (Trade and TradePolicy), and Laravel discover it automatically., Comment.

GATE WITH POLICY WITHOUT MODEL

所以这里的一切都是正确的,但问题是你不能这样使用它,你没有专用于此策略的模型,所以你可以使用Gate与policy。


class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
// Don't add it here while you don't have model
// Auto discover work like this method, so they're both same.
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
// Here you need to define a new gate related to policy.
Gate::define('yourPolicy', [YourPolicy::class, 'yourPolicyMethod i guess']);
Gate::define('yourPolicy', `AppPoliciesYourPolicy::class`);
Gate::define('yourPolicy', YourPolicy::class);
// one of above ways base on laravel version.
// or
Gate::define('yourPolicy', function (User $user, Request $request){
});
}
}

可以看到,在// or之后,定义gate的方式类似于策略,但是,第一种方式是您的方式。

And in controller:

public function store(StoreTradeRequest $request, StoreTradeService $service)
{
if (! Gate::allows('yourPolicy', $request->all())) {
...
}
}

编辑02:Plain Old PHP Object (POPO)OOP的一点基础知识。

普通旧PHP对象(POPO)

好了,既然你想坚持你的方法,我只能考虑在如何使用模型的基本思想中做这个。

当我说策略意味着与模型一起工作时,如果你没有一个共同的类呢?

假设,你的策略不需要Trade,它的目的只是处理请求的事情,所以这个想法应该很容易做下面的事情:

class Request
{
public array $request;
public function __construct(array $request)
{
$this->request = $request;
}
}

现在让我们使用php artisan make:policy RequestPolicy创建一个新策略,并注册它或测试它是否自动发现(如果没有,您可以像下面这样将它添加到protected $policies)。

class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Request::class => RequestPolicy::class,
];
}

然后移动你的登录到RequestPolicy:

class RequestPolicy
{
public function store(User $user, Request $request): bool
{
return $user->id == $request['trader_id'];
}
}

当然在Controller中:

public function store(StoreTradeRequest $request, StoreTradeService $service)
{
$this->authorize('store', new Request($request->(all)));
// ...
}

现在,通过这种方式,这也是一种更好的方式,你可以认识到政策的目的,因为如果贸易政策与贸易模式无关,那就没有意义了。

另一方面,新策略有意义,它应该处理与非模型事物相关的事情,唯一的问题是为你的方法命名问题,在这种情况下,你可以使用'storeTrade'之类的东西,而不是'store'。

在这种情况下,新策略将灵活地适应您试图实现的其他策略。

当然,当你试图导入Request命名空间时,不要忘记检查它,因为它应该像AppModelsRequest

您可以在策略类中为用户使用可选的类型提示,如下所示:

public function store(?User $user, array $request): bool
{
return true;
}

你可以在这里阅读;)