ガイド

セキュリティ

認証、認可、バリデーションについて学びます。

認証

Orionは現時点で認証機能を提供しておらず、アプリケーションに必要な認証機能のセットアップは開発者の責任であることを前提としています。この目的には、Laravel PassportまたはLaravel Sanctumの利用を推奨します。

認可

モデルコントローラーとリレーションコントローラーはいずれも、現在認証されているユーザーが特定のアクションを実行できるかどうかの判定にモデルポリシーを利用します。

推奨はされませんが、状況によっては特定のコントローラーで認可チェックを無効にしたい場合があります。その場合はOrion\Concerns\DisableAuthorizationトレイトを使用します。

<?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ガード)での利用

デフォルトでは、認可のために現在認証されているユーザーを解決する際にapiガードが使用されます。

ただし、config/orion.phpauth.guardを設定するか、コントローラーのresolveUserメソッドをオーバーライドすることで、ユーザーの解決方法を変更できます。

<?php

namespace App\Http\Controllers\Api;

use App\Models\Post;

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

     /**
     * ガードに基づいて現在認証されているユーザーを取得します。
     *
     * @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 は親エンティティです
    {
        // チェックはリレーションエンティティ $postMeta ではなく
        // 親エンティティ $post に対して実行されることに注意してください
        return Gate::forUser($user)->inspect('update', $post); 
    }
    
    public function create($user, $post)
    {
        return Gate::forUser($user)->inspect('update', $post);
    }
}

ポリシークラスのカスタマイズ

同じモデルに対して、コントローラーやシナリオごとに異なる認可ルールを使用することはよくあります。デフォルトでは、ポリシーはLaravelの組み込み機能によって解決されます。特定のポリシーをコントローラーで使用したい場合は、protected $policyまたはprotected $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;
}

バリデーション

リクエストクラスは、Illuminate\Foundation\Http\FormRequestではなく、必ずOrion\Http\Requests\Requestクラスを継承する必要があります。

storeおよびupdateエンドポイントへの受信リクエストデータをバリデーションするために、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のサービスコンテナによって結合され、メソッドシグネチャに明示的に指定した場合と同じように、storeおよびupdateメソッドでリクエストデータのバリデーションに使用されます。

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

バリデーションルール

storeupdate操作のルール定義

Orionが提供するOrion\Http\Requests\Requestクラスには、バリデーションルールを指定するためのメソッドがいくつか用意されています。

storeupdateの両方のエンドポイントに共通のルールを定義するには、commonRulesメソッドを使用します。 エンドポイント固有のルールを定義したい場合は、storeRulesおよびupdateRulesメソッドを使用します。

storeRulesおよびupdateRulesメソッドで指定した特定のフィールドのルールは、同じキーが両方に含まれる場合、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エンドポイントにリクエストが送られた場合は、updateRulesメソッドに他のルールが定義されておらず、commonRulesメソッドでtitleフィールドが必須と指定されているため、titleフィールドのみが必須になります。

リレーション固有の操作のルール定義

リレーション固有のエンドポイントに対してもルールを定義できます: associateRulesattachRulesdetachRulessyncRulestoggleRulesupdatePivotRules

これらのメソッドで指定したルールは、commonRulesメソッドのルールとマージされません

バッチ操作のルール定義

バッチエンドポイントに対してもルールを定義できます: batchStoreRulesbatchUpdateRules

バリデーションメッセージ

特定のエンドポイントに対してルールを設定できるのと同様に、バリデーションメッセージもカスタマイズできます。

storeupdate操作のバリデーションメッセージのカスタマイズ

storeupdateの両方のエンドポイントに共通のメッセージを定義するには、commonMessagesメソッドを使用します。 エンドポイント固有のメッセージを定義したい場合は、storeMessagesおよびupdateMessagesメソッドを使用します。

storeMessagesおよびupdateMessagesメソッドで指定した特定のフィールドのメッセージは、同じキーが両方に含まれる場合、commonMessagesメソッドのメッセージを上書きします。

リレーション固有の操作のバリデーションメッセージのカスタマイズ

リレーション固有のエンドポイントに対してもメッセージをカスタマイズできます: associateMessagesattachMessagesdetachMessagessyncMessagestoggleMessagesupdatePivotMessages

これらのメソッドで指定したメッセージは、commonMessagesメソッドのメッセージとマージされません

バッチ操作のバリデーションメッセージのカスタマイズ

バッチエンドポイントに対してもメッセージをカスタマイズできます: batchStoreMessagesbatchUpdateMessages

リクエストデータの取得

デフォルトでは、エンティティの作成または更新時に、すべてのリクエストデータが取得され、モデルのfillメソッドに渡されます。

ただし、バリデーション済みのデータのみを渡すことも可能です。そのためには、orion.php設定ファイルでuse_validatedtrueに設定します。