指南

安全

了解认证、授权与验证。

认证

Orion 目前不提供任何认证功能,认证能力的搭建由开发者自行负责。我们推荐使用 Laravel PassportLaravel Sanctum 来实现这一目的。

授权

模型控制器和关联控制器都依赖模型策略来判断当前认证用户是否被允许执行某些操作。

虽然不建议这样做,但在某些情况下,你可能希望在特定控制器上禁用授权检查。为此,可以使用 Orion\Concerns\DisableAuthorization trait。

<?php

namespace App\Http\Controllers\Api;

use App\Models\Post;
use Orion\Concerns\DisableAuthorization;

class PostsController extends ApiController
{
    use DisableAuthorization;

    /**
     * @var string $model
     */
    protected $model = Post::class;
}

配合 Sanctum(或其他自定义 Auth guard)使用

默认情况下,授权时使用 api guard 来解析当前认证用户。

不过,你可以通过在 config/orion.php 中设置 auth.guard,或在控制器上重写 resolveUser 方法,来改变用户的解析方式。

<?php

namespace App\Http\Controllers\Api;

use App\Models\Post;

class PostsController extends ApiController
{
    /**
     * @var string $model
     */
    protected $model = Post::class;

     /**
     * 基于守卫(guard)获取当前已认证的用户。
     *
     * @return \Illuminate\Contracts\Auth\Authenticatable|null
     */
    public function resolveUser()
    {
        return Auth::guard('sanctum')->user();
    }
}

授权父实体

关联操作会向策略传递一个额外参数——父实体。你可以利用该参数设置额外的检查,判断用户是否被授权在给定父实体的上下文中对关联实体执行某些操作。

class PostPolicy
{
    public function update($user, $post)
    {
        return $post->user_id === $user->id;
    }
}

class PostMetaPolicy
{
    public function update($user, $postMeta, $post) // <---- 这里的 $post 是父实体
    {
        // 请注意,此检查是针对父实体 $post 执行的,
        // 而不是关联实体 $postMeta
        return Gate::forUser($user)->inspect('update', $post); 
    }
    
    public function create($user, $post)
    {
        return Gate::forUser($user)->inspect('update', $post);
    }
}

自定义策略类

同一模型在不同控制器或场景中使用不同的授权规则是很常见的。默认情况下,策略由 Laravel 通过其内置机制解析。不过,如果你希望为某个控制器使用特定的策略,请相应地设置 protected $policyprotected $parentPolicy 变量:

模型控制器

<?php

namespace App\Http\Controllers\Api;

use App\Models\Post;
use App\Policies\CustomPostPolicy;

class PostsController extends ApiController
{
    /**
     * @var string $model
     */
    protected $model = Post::class;

    /**
     * @var string $policy
     */
    protected $policy = CustomPostPolicy::class;
}

关联控制器

<?php

namespace App\Http\Controllers\Api;

use App\Models\Team;
use App\Policies\CustomPostPolicy;
use App\Policies\CustomTeamPolicy;
use Orion\Http\Controllers\RelationController;

class TeamPostsController extends RelationController
{
     /**
     * @var string $model
     */
    protected $model = Team::class; // 或 "App\Models\Team"
    
    /**
     * 在 Post 模型上定义的关联名称
     */
    protected $relation = 'posts';

    /**
     * @var string $parentPolicy
     */
    protected $parentPolicy = CustomTeamPolicy::class;

   /**
     * @var string $policy
     */
    protected $policy = CustomPostPolicy::class;
}

验证

请求类必须继承 Orion\Http\Requests\Request 类,而不是 Illuminate\Foundation\Http\FormRequest

为了验证发送到 storeupdate 端点的请求数据,Orion 会按照类名模式 App\Http\Requests\<model>Request 查找资源模型对应的请求类

例如,如果你有一个 App\Models\Message 模型,对应的请求类就是 App\Http\Requests\MessageRequest

如果你的应用中请求类的命名不遵循这一约定,或者你只是想更明确地指定,可以将控制器上的 protected $request 属性设置为请求类的完全限定类名。

<?php

namespace App\Http\Controllers\Api;

use App\Models\Message;
use App\Http\Requests\CustomMessageRequest;

class MessagesController extends ApiController
{
    /**
     * @var string $model
     */
    protected $model = Message::class;

    /**
    * @var string $request
    */
    protected $request = CustomMessageRequest::class;
}

随后,请求类会通过 Laravel 的服务容器进行绑定,并在 storeupdate 方法中用于验证请求数据,效果与在方法签名中显式声明完全相同:

public function store(CustomMessageRequest $request)
{
    ...
}

验证规则

storeupdate 操作定义规则

Orion 提供了 Orion\Http\Requests\Request 类,其中包含一系列用于指定验证规则的方法。

要为 storeupdate 两个端点定义共用规则,可以使用 commonRules 方法。 如果你想定义特定于某个端点的规则,可以使用 storeRulesupdateRules 方法。

如果 storeRulesupdateRules 方法与 commonRules 方法中包含相同的键,则前者中为该字段指定的规则会覆盖 commonRules 方法中的规则。
<?php

namespace App\Http\Requests;

use Orion\Http\Requests\Request;

class PostRequest extends Request
{
    public function commonRules() : array
    {
        return [
            'title' => 'required'
        ];
    }

    public function storeRules() : array
    {
        return [
            'status' => 'required|in:draft,review'
        ];
    }
}

在这个示例中,当请求发送到 store 端点时,titlestatus 两个字段都是必填的。而当请求发送到 update 端点时,只有 title 字段是必填的,因为 updateRules 方法中没有定义其他规则,而 title 字段在 commonRules 方法中被标记为必填。

为关联专属操作定义规则

你还可以为关联专属端点定义规则:associateRulesattachRulesdetachRulessyncRulestoggleRulesupdatePivotRules

在这些方法中指定的规则不会commonRules 方法中的规则合并。

为批量操作定义规则

你还可以为批量端点定义规则:batchStoreRulesbatchUpdateRules

验证消息

就像可以为特定端点配置规则一样,也可以自定义它们的验证消息。

storeupdate 操作自定义验证消息

要为 storeupdate 两个端点定义共用消息,可以使用 commonMessages 方法。 如果你想定义特定于某个端点的消息,可以使用 storeMessagesupdateMessages 方法。

如果 storeMessagesupdateMessages 方法与 commonMessages 方法中包含相同的键,则前者中为该字段指定的消息会覆盖 commonMessages 方法中的消息。

为关联专属操作自定义验证消息

你还可以为关联专属端点自定义消息:associateMessagesattachMessagesdetachMessagessyncMessagestoggleMessagesupdatePivotMessages

在这些方法中指定的消息不会commonMessages 方法中的消息合并。

为批量操作自定义验证消息

你还可以为批量端点自定义消息:batchStoreMessagesbatchUpdateMessages

获取请求数据

默认情况下,在存储或更新实体时,会获取全部请求数据并传入模型的 fill 方法。

不过,也可以只传入已验证的数据。为此,请在 orion.php 配置文件中将 use_validated 设置为 true