ユーザー権限のチェックはどこで、MVCで誰によって行われますか?


26

モデルまたはコントローラーでユーザー許可チェックを行う必要がありますか?そして、誰が許可チェック、Userオブジェクト、またはUserManagementヘルパーを処理する必要がありますか?

それはどこで起こるべきですか?

コントローラーのチェックイン:

class MyController {
  void performSomeAction() {
    if (user.hasRightPermissions()) {
      model.someAction();
    }
  }
  ...

コントローラーにチェックがあると、モデルをシンプルなアクションにするのに役立ち、すべてのロジックをコントローラーに保持できます。

モデルのチェックイン:

class MyModel {
  void someAction() {
    if (user.hasRightPermissions()) {
      ...
    }
  }
  ...

モデルにチェックを入れることにより、モデルを複雑にしますが、コントローラーで想定されていない操作をユーザーが誤って許可しないようにします。

そして誰によって?

場所に落ち着いたら、誰がチェックするべきですか?ユーザー?

Class User {
  bool hasPermissions(int permissionMask) {
    ...
  }
  ...

しかし、ユーザーがアクセスできる内容を知ることは、実際にはユーザーの責任ではないので、おそらくヘルパークラスでしょうか?

Class UserManagement {
  bool hasPermissions(User user, int permissionMask) {
    ...
  }
  ...

質問に1つだけ質問するのはよくあることですが、これらは一緒にうまく答えられると思います。

回答:


20

いつものように、「依存する」

  • 許可チェックは機能します 仕事、それはそれらを置くと便利ですどこにでも
  • しかし、技術的な質問をしている場合、答えは「チェックを実行するために必要なデータを所有するオブジェクトにチェックを入れる」(おそらくコントローラーです)かもしれません。
  • しかし、哲学的な質問をしている場合は、別の答えをお勧めしますユーザーが実行を許可されていないアクションを表示しないでください

そのため、後者の場合、コントローラーにブールプロパティとして実装されたアクセス許可チェックを行い、そのプロパティを、アクションを制御するユーザーインターフェイスのボタンまたはパネルのVisibleプロパティにバインドすることができます。

ユーザーとして、私が実行できないアクションのボタンを見るのはイライラします。私は楽しみから取り残されているように感じます;)


アプリケーションは、コントロールを非表示にせず、無効にするという例外を除いて、3番目のシナリオを実装します。残念ながら、それはすべてWinformsのコードビハインドで行われているため、OPの質問には実際には関係ありません。
デイブネイ

11
「実行できないアクションのボタンを見るのはイライラする」 ->自分の投稿に賛成してみてください:)
ローワンフリーマン14

5
ユーザーが実行できないアクションのボタンを単純に非表示にするだけでは不十分であり、サーバーはすべてのリクエストの許可を確認する必要があります。3番目の箇条書き項目は「代替回答」ではなく、サーバー側の権限の確認に加えて行うべきことです。
フリム

要求がサーバーによって処理される場合、@ Flimmは同意しました。具体的な質問は、コントローラークラスに関するものでした
スティーブンA.ロウ

7

セキュリティは分野横断的な関心事であるため、複数の層で実装する必要があります。以下はMVCの例ですが、この概念は他のアーキテクチャやパターンに適用されるため、実施するポイントを特定するだけです。

それはどこで起こるべきですか?

ビューには、権限に基づいて、一部のユーザーに対して表示する必要があるかどうかを示すUI要素(ウィジェット、ボタン、メニューなど)が含まれる場合があります。すべてのビューがこれを単独で処理することは望ましくないため、これはビューエンジンの責任である可能性があります。承認を行っている要素の種類に応じて、この責任を別の場所に移します。たとえば、いくつかの項目を表示する必要があるものとしないものがあるメニューを考えてください。アイテムはどこかでリストとして実装され、権限に基づいてそのリストをフィルタリングしてからビューに転送できます。

コントローラーはリクエストに応答するため、ユーザーがアクションを実行する権限を持っていない場合は、アクションが呼び出される前にチェックする必要があり、コントローラーに保持するのではなく、アクション呼び出し側に責任を移します。これには、コントローラーをクリーンに保つという利点があり、アクセス許可に何らかの変更があった場合、それらの変更を適用するためにコントローラーをふるいにかける必要はありません。

リソースは権限に基づいて表示されます。データベースからすべてを引き出してからパーミッションを適用したくないので、これは通常データベースレベルで行われます

ご覧のとおり、許可する内容に応じて、これを行うべき場所が異なります。セキュリティポリシーが変更されたときに、できればアプリケーションのコードを変更せずに簡単に適用できるように、目標はできるだけ目立たないようにすることです。これは、権限セットがかなり小さく、頻繁に変更されない小さなアプリケーションには有効ではない場合があります。ただし、エンタープライズアプリケーションでは、話はまったく異なります。

誰がそれをすべきですか?

明らかにモデルではありません。各層には、承認を処理する実施ポイントが必要です。上記の斜体のテキストは、各レベルで考えられる施行ポイントを強調しています。

見ていXACMLを。そのまま実装する必要はありませんが、従うことができるいくつかの指示を与えてくれます。


これが最良の答えです。なんらかの理由で、トップと他はコントローラーとビュー、またはビューとモデルの違いを扱っていますが、これはOPが求めているものではありません。ありがとう!
redFur

1

私は次のスキームを使用します。ほとんどのユーザーパーミッションチェックは、2つの一般的なケースに分けることができます。

  • パラメータアクションを確認せずにユーザーロールに基づいてコントローラーアクションへのユーザーアクセスが呼び出される、
  • 特定のユーザーと特定のモデルの間の任意のロジックまたは関係に基づいて、モデルへのユーザーアクセス。

通常、属性のチェックなしでのコントローラーアクションへのアクセスは、MVCフレームワークで実装されます。これはまったく簡単です。ルールを定義し、ユーザーが役割を持ちます。ユーザーがルールでその役割を検索するアクションの許可を持っていることを確認するだけです。

特定のモデルへのユーザーアクセスは、モデルで定義する必要があります。(アクターは基本ユーザークラスです。顧客、売り手、またはゲストのいずれかであると想定します。)

interface ICheckAccess
{
    public function checkAccess(Actor $actor, $role);
}

class SomeModel implements ICheckAccess
{
    public function checkAccess(Actor $actor, $role)
    {
        // Your permissions logic can be as sophisticated as you want.
    }
}

そのロジックをモデルに配置すると、いくらかの利益がもたらされます。アクセスチェックメソッドを継承できます。追加のクラスを作成する必要はなく、一般的なOOPの利点を使用できます。

次に、アクセスチェックを単純化するために、単純化と適切なスタイルのために、ほとんど常に既に実装されているいくつかの仮定を採用します。

  • 通常、コントローラーはいくつかのモデルクラスに関連しています。
  • アクセスがチェックされるアクションは、単一のモデルIDをパラメーターとして受け取ります。
  • このパラメーターは、基本コントローラークラスのメソッドから常に均一にアクセスできます。
  • idアクションが実行するモデルに対応するコントローラーにアクションが配置されます。

これらの仮定により、モデルIDを使用するアクションを特定のモデルインスタンスに関連付けることができます。実際、ほとんどのアクションは、上記の仮定に合わせて簡単に変換および移動できます。

次に、いくつかの基本抽象コントローラークラスを定義して継承する必要があります。

abstract class ModelController
{
    // Retrieve model from database using id from action parameter.
    public abstract function loadModel($id);

    // Returns rules for user role to pass to SomeModel::checkAccess()
    // Something like array('view' => 'viewer', 'delete' => 'owner', 'update' => 'owner')
    public abstract function modelRules();

    public abstract fucntion getIdParameter();

    public function filterModelAccess()
    {
        $id = $this->getIdParameter();
        if(!$this->checkModelAccess($id))
            throw new HttpException(403);
    }

    public function checkModelAccess($id)
    {
        $model = $this->loadModel($id);
        $actor = My::app()->getActor();
        $rules = $this->modelRules();
        $role = $rules[My::app()->getActionName()];
        return $model->chechAccess($actor, $role);
    }
}

メニューを作成し、リンクを表示するかどうかを決定するときに、SomeController :: checkModelAccess($ id)メソッドを呼び出すことができます。


PHPでごめんなさい。
ジョージソヴェト

1

モデルビューの両方で

ビュー内 -現在のユーザーに制限されているUI要素はUIに表示されないため

(たとえば、「削除」ボタンは適切な権限を持つユーザーに表示される必要があります)

モデルでは -あなたのアプリにはおそらく何らかのAPIがあるのでしょうか?APIは権限もチェックする必要があり、おそらくモデルを再利用します。

(たとえば、UIに「削除」ボタン「http:/ server / API / DeleteEntry / 123」APIメソッドが同時にあるなど


コントローラーよりもなぜモデルを選んだのですか?
フリム

ほとんどの場合、コントローラーで表示、モデル化するのではなく、表示する理由がわかりません。
VP。

@VPコントローラーはUI要素を表示/非表示にする権限を持ちません(bool-varをビューに渡す以外)
-jitbit

私は知りません、どこでも通常はコントローラー層で行われます、それが私が興味を持った理由です。
VP。

0

MVCはプレゼンテーションパターンです。そのため、ビューとコントローラーにはプレゼンテーションに関する責任のみが必要です。エキスパートモード、実験的なUI機能、さまざまなデザインなど、一部の権限はプレゼンテーションに適用されます。これらはMVCコントローラーで処理できます。

他の多くの種類の権限は、アプリケーションのいくつかのレイヤーに関連しています。たとえば、データの表示のみが可能で、変更はできないユーザーが必要な場合:

  • プレゼンテーション層は編集機能を非表示にする必要があります
  • とにかく編集機能が呼び出された場合、これは(ドメインの特定の部分ではなく、ビジネス層のアプリケーション固有の部分-TrainEditorであり、Trainではなく)検出される可能性があり、おそらく例外を引き起こす
  • データアクセスレイヤーも書き込みをチェックできますが、ビジネスレイヤーの知識をすぐに必要とするより複雑な種類のアクセス許可の場合は良い考えです。

このアプローチにはいくつかの重複があります。しかし、プレゼンテーションは通常揮発性であるため、プレゼンテーション層が意図したとおりに機能する場合の冗長なチェックを意味する場合でも、通常はアプリケーションのより安定した部分で許可をチェックすることをお勧めします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.