web-dev-qa-db-ja.com

laravel RESTful APIのきめ細かなデータレベルの権限

問題:

サービスから返されるプロパティへのアクセスを制限したい。

詳細:

問題なく動作するルートレベルの権限があります。

たとえば、/product/{id}を表示できるユーザーの場合、そのユーザーにはpurchasePriceプロパティを表示する権限がある場合とない場合があります。 (権限がない場合、空であるか、JSON応答に存在しないかのいずれかです)デフォルトでは、laravelはモデルをロードするとレコード全体を返します。

私たちが試したこと:

現在、権限に基づいて動的に$visible[]にデータを入力しており、すべてのフィールドのリストと、読み取り/書き込みに必要な権限を確認できます。

私の質問:

これを行うより良い方法はありますか?私たちは車輪を再発明していますか、それともこれは合理的なアプローチのように見えますか?

2
mkaatman

エンティティをAPI応答モデルから分離します。これはSRP(単一責任原則)の場合です。エンティティの仕事は、DBアクセスを便利にすることです。あなたはそれに2つの責任を追加し、SRPに違反しています:

  • 権限の適用
  • パブリックインターフェイスとして機能する

つまり、この回答には2つの部分があります。

公開APIを持っている

パブリックAPIは、ユーザーに明記されていない限り、安定しており、下位互換性がある必要があります可能な限り最も明示的な方法で。つまり、パブリックAPIを変更するコードベースの変更は、本番環境にリリースする前に、下位互換性について慎重に確認する必要があります。現在のアプローチでは、そうするのが非常に困難になります。エンティティのプロパティの名前を変更したいとします。 IDEはすべての使用法をキャッチして名前を変更しました。しかし、APIを使用する他のコードについてはどうですか?それでも古い名前を探しているので壊れます。すべての情報がそこにある限り、エンティティを変更してパブリックAPIに影響を及ぼさないことがここで本当に必要です。解決策:APIに個別のクラスを用意します。エンティティごとに、(現在)を反映する別のクラスを用意しますエンティティ。APIから入力を受け取ったら、JSONをこれらの中間インスタンスに変換します。検証を行ってその後のみデータをエンティティにコピーします。データを渡すときは、まずエンティティをそれらの中間クラスに変換しますそして、それらをJSONに変換します。はい、それはより多くの作業を意味します。ただし、APIを公開するとすぐに、柔軟性が得られます100%確実に必要になります。この作業は、30より簡単に実行できるようになりました。後で機能します。

権限の適用

これで、この責任をAPI表現クラスに含めるか、個別に行うかを決定できます。これを、エンティティから表現クラスにデータをコピーするプロセスに含めることもできます。それは本当にあなたのコードベース、チーム、そして好みに依存します。そのコードをどこに配置しても、SRPに違反していないことを確認してください。

パフォーマンス

すでに述べたように、権限のために表示されないフィールドをDBからフェッチしないことさえ可能です。通常のフィールドの場合、パフォーマンスへの影響は無視できます(数KBのBLOBフィールドについて話している場合を除く)。しかし、これが本当に重要なのは関連するエンティティです。とにかく使用されないために3つの結合を回避できる場合、それは決定的で非常に高速です。この問題に関するiipavlovの回答を参照してください。

1
marstato

モデルに動的スコープを作成します( https://laravel.com/docs/5.1/eloquent#query-scopes )。これは、入力として権限を取得し、クエリ選択を変更して、特定の権限の許可されたフィールド。

0
iipavlov