我有一个正在逐步构建的 API,以包含我的平台的所有重要业务逻辑和行为。我需要允许或禁止某些操作,但不是基于尝试完成操作的用户的身份。我正在尝试确定实现此逻辑的最佳模式。
我的所有操作都是由位于 app/Service 目录中的各种服务类执行的。例如 - EventService 类负责与事件记录相关的所有操作。这里的一个用例可能是,作为对 cancelEvent(Event $event) 的 API 调用的一部分,必须首先进行检查以确保没有人注册到该事件 - 如果他们注册了,这是不允许的。
这里最好的解决方案是什么?在我看来,Gates和Policies更多的是授权特定用户查看他们是否可以执行请求的操作。我是否应该在服务类中构建“制衡”并阻止其中的操作?或者是否可以创建不关心用户记录的策略(然后我可以在其他地方重用),并且可能在控制器级别检查这些策略?或者还有其他我没有想到的模式?我也看到人们将其写入雄辩的模型中,但这对我来说并不是真正合适的地方。
这里也很重要的是,如果遭到拒绝,能够返回信息丰富的响应。例如“此活动无法取消,因为有 2 个用户注册”。这将返回给 api 调用者,然后反馈给最终用户。
有“Laravel 方式”可以做到这一点吗?
策略可以作为您所描述的内容的基础,并且将是一种 Laravel 方式(鉴于他们在 授权文档 中说了这么多)。尽管它们是通过用户上下文调用的,但不需要在策略内部使用。我认为对您的案例有价值的政策的一些好处:
我认为第三点可能是您如何获取有关政策失败原因的详细信息。尽管我非常不愿意通过引用传递,但这可能值得例外,以便使用策略框架并获取原因上下文。
这是一个草图:
some.blade.php
@can('doSomething', $someModel)
You can do the thing.
@else
Sorry, you cannot do the thing.
@endcan
Http/Controllers/SomeController.php
public function doAction() {
$reason = null;
if (auth()->user()->can('doSomething', $someModel, $reason)) {
return 'Done!';
} else {
return 'Not done because ' . $reason
}
}
class SomeModelPolicy
{
use HandlesAuthorization;
public function doSomething(User $user, SomeModel $someModel, string &$reason = null): bool
{
if ($someModel->hasSomeState()) {
return true;
} else {
$reason = 'SomeModel does not have some state';
return false;
}
}
}
需要考虑的一件事是,您仍然需要正在验证的规则的定义,例如我的
$someModel->hasSomeState()
,并且您可能希望将它们封装在模型上,以便调用单个、清晰的业务规则(尽管是一个操作)可能需要检查多个规则)。这有点像“瘦控制器,胖模型”的想法。瘦身政策也能起到同样的作用。
这是基于用例的快速指南:
Authz=授权=权限