ユーザー権限チェックは、モデルまたはコントローラーのどちらで行う必要がありますか?そして、誰が権限チェック、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) {
...
}
...
たった一つの質問をするのはよくあることですが、これらは一緒にうまく答えられると思います。
いつものように、「依存する」
したがって、後者の場合は、ブール型プロパティとして実装されたコントローラーで権限チェックを行い、そのプロパティを、アクションを制御するユーザーインターフェイスのボタンまたはパネルのVisibleプロパティにバインドします。
ユーザーとして、私が実行できないアクションのボタンを表示するのはイライラします。私は楽しみから取り残されているような気がします;)
セキュリティは分野横断的な懸念事項であるため、複数のレイヤーで実装する必要があります。以下はMVCの例ですが、その概念は他のアーキテクチャーやパターンに適用されるため、適用のポイントを特定するだけです。
Viewsには、ユーザーの権限に基づいて、一部のユーザーに対して表示または非表示にする必要があるUI要素(ウィジェット、ボタン、メニューなど)が含まれる場合があります。 view engineの責任である可能性があります。すべてのビューがこれを単独で処理することを望まないからです。承認を行う要素のタイプに応じて、この責任を別の場所に移動します。たとえば、表示する必要がある項目と表示しない項目があるメニューを考えてみます。アイテムはどこかにリストとして実装され、権限に基づいてそのリストをフィルタリングしてから、ビューに転送できます。
コントローラはリクエストに応答するため、ユーザーがアクションを実行する権限を持っていない場合は、アクションが呼び出される前に確認して責任を移動する必要がありますアクションの呼び出し元をコントローラーに保持するのではなく、これには、コントローラーをクリーンな状態に保つという利点があります。また、アクセス許可に何か変更があった場合、それらの変更を適用するためにコントローラーをふるいにかける必要はありません。
リソースは、権限に基づいて表示されます。これは通常、databaseレベルで行われます。これは、データベースからすべてをプルしてアクセス許可を適用する必要がないためです。
ご覧のように、承認する対象に応じて、これを行う必要のある場所がいくつかあります。セキュリティポリシーが変更されたときに、できればアプリケーションのコードを変更せずに簡単に適用できるように、目標はできるだけ控えめにすることです。これは、権限セットがかなり小さく、頻繁に変更されない小さなアプリケーションには有効でない場合があります。しかし、エンタープライズアプリケーションでは、話はかなり異なります。
明らかにモデルではありません。各層には、承認を処理する実施ポイントが必要です。上のイタリック体のテキストは、各レベルの可能な実施ポイントを強調しています。
[〜#〜] xacml [〜#〜] をご覧ください。そのまま実装する必要はありませんが、従うことができるいくつかの指示が得られます。
以下のスキームを使用しています。ほとんどのユーザー権限チェックは、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を使用するアクションを特定のモデルインスタンスに関連付けることができます。実際、ほとんどのアクションは、上記の仮定に合わせて簡単に変換および移動できます。
次に、いくつかの基本抽象コントローラークラスを定義して継承する必要があります。
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)メソッドを呼び出すことができます。
ビュー内-現在のユーザーに制限されているUI要素をUIに表示しないため
(たとえば、「削除」ボタンは適切な権限を持つユーザーに表示されます)
モデル内-アプリにはおそらく何らかのAPIが含まれているためですよね? APIは権限もチェックする必要があり、おそらくモデルを再利用します。
(たとえば、UIに「削除」ボタンがあるand「http:/ server/API/DeleteEntry/123」APIメソッドと同時に
MVCはプレゼンテーションパターンです。そのため、ビューとコントローラーは、プレゼンテーションに関する責任のみを持つ必要があります。エキスパートモード、実験的なUI機能、さまざまなデザインなど、一部の権限はプレゼンテーションに適用されます。これらはMVCコントローラーで処理できます。
他の多くの種類の権限は、アプリケーションのいくつかの層に関連しています。たとえば、データの表示のみが可能で変更はできないユーザーが必要な場合:
このアプローチにはいくつかの重複があります。ただし、プレゼンテーションは通常揮発性であるため、プレゼンテーション層が意図したとおりに機能する場合の冗長チェックを意味する場合でも、アプリケーションの通常はより安定した部分で権限をチェックするための良いケースを作ることができます。