web-dev-qa-db-ja.com

ロールベースのアクセス権をWebアプリケーションに保存する方法は?

現在、会社、連絡先、プロジェクト、サブプロジェクトなどのさまざまなモジュールを扱うWebベースのCRMタイプシステムに取り組んでいます。典型的なCRMタイプシステム(asp.net Webフォーム、C#、SQL Serverバックエンド)。基本的にユーザーが1つ以上のロールを持つことができるように、ロールベースのセキュリティを実装する予定です。

ロールは、最初に次のようなモジュールタイプによって分類されます。

-会社

-連絡先

そして、そのモジュールのアクションによって、たとえば、各モジュールは次のようなテーブルになります。

Role1 Example:

    Module   Create  Edit        Delete   View
    Company   Yes    Owner Only    No     Yes
    Contact   Yes    Yes           Yes    Yes

上記の場合Role1には2つのモジュールタイプ(会社と連絡先)があります。会社の場合、このロールに割り当てられたユーザーは、会社の作成、会社の表示、作成したレコードの編集のみが可能で、削除はできません。モジュール連絡先のこの同じ役割に対して、このユーザーは連絡先の作成、連絡先の編集、連絡先の削除、および連絡先の表示(基本的には完全な権限)を行うことができます。

システムに入ってユーザーの役割を次のようなものとセッションするのが最善であると思います:

List<Role> roles;

Roleクラスには、ある種のList<Module> modules;(会社、連絡先などを含めることができます)?以下の影響があるもの:

class Role{
string name;
string desc;
List<Module> modules;
}

また、モジュールアクションクラスには、モジュールごとに一連のアクション(作成、編集、削除など)があります。

class ModuleActions{
List<Action> actions;
}

アクションには、ユーザーが権限を実行できるかどうかの値があります。

class Action{
string right;
}

大まかなアイデアですが、アクションが列挙型であり、ModuleActionはおそらくList<x, y>。私の主な質問は、このタイプのアプリケーションにこの情報を格納するための最良の方法は何ですか?それをユーザーセッション状態に格納する必要があります(ユーザーに関連するものを管理するセッションクラスがあります)。通常、これはアプリケーション(global.asax)の初期読み込み中に読み込みます。このセッションに簡単に取り組むことができます。

または、これは各モジュールのページ読み込みイベント(会社のページ読み込みなど)で読み込まれる必要があります。最終的には、ユーザーの役割に基づいてさまざまなボタン/ divを非表示/再表示できるようにする必要があります。そのため、これをセッション経由でロードすることを考えました。

どんな例やポイントも素晴らしいでしょう。

6
JonH

まあ、私はあなたのデザインは素晴らしいと思います。私はあなたに役割を保存する方法について単純なことだけをお勧めします。ここに、ほぼ同じ概念のシステムがあります。名前のとおりの役割には基づいていません。

したがって、ユーザーが持っているアクセス許可を格納するMapタイプのオブジェクトを持つユーザーセッションオブジェクトがあります。そして、このMapオブジェクトは塗りつぶされますdemmand上次のようなものになります:

_public class UserSession {
    HashMap<Application, Action> map;

    public boolean hasPermissionApp( Application app ){
        if ( !map.containsKey(app) ){
            //check if the user has the permission on the DB or whatever you store it
            //if it has add it to the map with the action that 
            //it came along and return true
            //if it hasn't return false
        }
        return true;
    }

    public boolean hasPermissionAction( Application app, Action act ) {
        if ( hasPermissionApp(app) ){
            if ( !map.get(app).containsKey(act) ){
                //check if the user has permission to that action of the app
                //if it has add to the map and return true
                //if not return false
            }
        }
        return false;
    }
}
_

そうすることで、ユーザーのアクセス許可を読み込み、それをdemmandによって格納し、ユーザーが持つすべてのアクセス許可セットでセッションオブジェクトをオーバーロードしないでください。

[〜#〜]編集[〜#〜]

OPがコメントについて尋ねたように:

  • 役割の権限を必要とするあらゆる種類のクリックイベントでこのハッシュマップを埋めますか?

答えはほぼこれです。ユーザーがアプリケーションにログインすると、ユーザーセッションオブジェクトが空になるので、ログインしているアプリケーションについて、ユーザーがアクセス権を持っているかどうかを確認し、アクセスできる場合は、そのアプリケーションによって呼び出された最初のアクションでマップに追加します。 「表示」と言いましょう。このアクションを使用すると、ユーザーは検索フォームを表示できます。

ここでは、2つの方法があります。あなたが尋ねたのはそれです!

  • ユーザーがこの「表示」アクションのようにイベントを起動するときに権限を確認します。検索、追加、キャンセルなどのボタンを使用してフォーム全体を表示できますが、ユーザーがボタンを押したときにのみ権限が確認されます。次に、マップに追加するか、その許可がないことを伝えるメッセージを彼に送信する必要があります。

  • アクションをレンダリングするときに権限を確認してください。フォームにボタンを表示するのは、ユーザーに適切なアクションが関連付けられている場合のみです。では、Richfacesのようなコンポーネントライブラリを使用しているとしましょう:

<a4j:commandButton rendered="#{userSessionObject.hasPermissionAction('appBla','search')}" ..... />

また、これはページの作成時に作成されるため、ページまたはその他のリソースに対して行われるすべてのチェック許可にマップが入力されます。

私のアプリケーションでは、2番目のアプローチを選択します。これは、ボタンにアクセスできないユーザーにボタンを表示することは意味がないと思うためです。

編集2

おそらく役に立つかもしれないことは、userSessionObjectのマップをクリーンアップするスレッドタイミング(構成可能な時間)をユーザーセッションに関連付けることです。そのため、管理者がそのユーザーへのアクセス許可を変更すると、そのユーザーのアクセス許可が自動的に更新されます。厳密にはプロンプトではありませんが、これはこの特定のシステムにとって許容できる要件でした。

3
Jorge Campos

私は(あなたとは異なる)テーブル/ディレクトリの数が固定されたシステムで作業していたので、あなた(またはファイルシステムやSQL DB)のようなロールベースのセキュリティスキーマは使用しませんでした。線形アクセスレベルを使用しました。高レベルでは、特に質問に関しては、状況は似ています。

それでも、クライアント側のどこにAccess Rightを格納しても、ソース(DB)の内容が正確に反映されているとは限りません。

  1. ユーザーがログインするときにアクセス権をロードします。セッションオブジェクトへのアクセス権の保存は問題ありません。
  2. バックエンドのロジックレイヤーで各アクションを検証する
  3. 追加:アクションが完了しない場合、バックエンドはアクセス権の変更に関するフィードバックを送信します
  4. 追加オプション1:フィードバックが受信されると、バックエンドは新しいアクセス権をエンコードするために別のチャンクを送信することもできます
  5. 追加オプション2:フィードバックが受信されると、フロントエンドはユーザーに再ログインを提案します
1
InformedA

ページの読み込み時にユーザー権限を取得することに関連するオーバーヘッドはほとんどないはずなので、そうします。セッションを使用して、ほとんどのものを保存しないでください。これにより、管理者が権限を動的に変更できるようになります(ユーザーが再度ログインする必要がなくなるため)。

詳細なロールインフラストラクチャを開発するのではなく、ユーザーにアクセス許可タグを割り当てるなど、もっと簡単なものを検討してみませんか。 company:create、company:editなど。これらは、現在のインフラストラクチャとまったく同じように解釈できます。ただし、これにより、パーミッションをより個別のアクション(たとえば、CRUD操作だけでなく)に割り当てることができるようになり、柔軟性がさらに向上します。

最後に、ユーザーが自分のアクションを送信するときに、クライアントで許可されているすべての権限もサーバーで確認する必要があります。私たちは単にクライアントを信頼することはできません。したがって、クライアント上でもサーバー上でも、ユーザーのアクセス許可タグを確認して正しいことを行います。クライアント側では、これはインターフェースの変更を意味するかもしれません。サーバー側では、これは、ユーザーがなんらかの理由で許可を回避したように見えるトランザクションを拒否することを意味する場合があります(これが許可されていない会社を作成しようとしたなど)。

0
Mario T. Lanza

セッションにはList<Action>を保存するのが最善だと思います。セッションの開始時にユーザーが持つ役割に基づいて、このリストを解決します。

権限が頻繁に変更されない限り、ユーザー権限はログインごとに更新するだけで十分です。

余談ですが、RoleList<Module>を持つように設計するのではなく、List<Action>にするようにしました。

0
nablex