Webアプリケーションにきめの細かい認可を実装する最良の方法は?
-
07-07-2019 - |
質問
私はRails Webアプリケーションで作業しており、現在約20人のユーザーによって使用されています。
一部のユーザーのみがアプリケーションの一部にアクセスできるため、acts_as_authenticatedプラグインを使用して実装した基本的な承認フレームワークが既に用意されています。
ユーザーの権限は、所属する部門によって異なるため、たとえば、管理者はアプリケーションのすべての部分にアクセスできますが、経理は経理関連の部分のみにアクセスでき、販売は販売関連の部分にのみアクセスできますなど。
一方、ユーザーには、権限が不十分なアクションへのリンクが表示されます。たとえば、営業部門の人はメインメニューに財務記録へのリンクが表示されますが、クリックしても何も起こりません。これは、知る限り、acts_as_authenticatedを使用してユーザー権限を照会する効率的な方法がないためです。
これを2つの方法で変更したい:
-
よりきめの細かい承認を導入したい。現在、承認はコントローラーレベルで行われます。アクションレベルまたはモデルレベルでこれを実行したいです。たとえば、営業部門の担当者は支払いを作成および更新できますが、削除はできません。
-
ユーザーの特権を効率的に照会できるようにしたいので、インターフェイスから不要な(混乱を招く)リンクを削除できます。
これを実装する最もエレガントな方法は何だと思いますか?
レール固有の回答は必要ありません。これをデータ駆動型アプリケーションに実装する方法を知りたいだけです。
最後に、現在の実装方法は次のとおりです。
def authorized?
current_user.role.foo? or current_user.role.bar?
end
これが私の最初のアイデアです。これを解決する最善の方法ではないと思います:
+------------+------------+---------+ | department | controller | action | +------------+------------+---------+ | accounting | payments | index | | accounting | payments | new | | accounting | payments | create | | accounting | payments | edit | | accounting | payments | update | | accounting | payments | destroy | | sales | payments | new | | sales | payments | create | | sales | payments | edit | | sales | payments | update | +------------+------------+---------+
または
+------------+----------+-------+--------+------+--------+--------+ | department | model | list | create | read | update | delete | +------------+----------+-------+--------+------+--------+--------+ | accounting | payments | TRUE | TRUE | TRUE | TRUE | TRUE | | sales | payments | FALSE | TRUE | TRUE | TRUE | FALSE | +------------+----------+-------+--------+------+--------+--------+
解決
承認の基本概念は、私が理解しているとおり、役割です。 役割はさまざまなことを表現できます:
- システム全体に対するユーザーの関係(たとえば、システムの管理者になるため)
- ユーザーと何らかのエンティティとの関係(例:コメントのモデレーターになる)
- 特定のエンティティへのユーザーの関係(たとえば、リソースの所有者になるため)
- その他の複雑な関係(例:リソースの所有者であるユーザーの友人になるため)
- ユーザーが何らかの属性を持っているか、何らかの特定の方法で何らかのメッセージに応答している(例:ティーンエイジャーになる)
非常にきめの細かい認可システムでは、上記の基準のいずれかに基づいてユーザーのロールを定義できます。さらに、ユーザーに複数のロールを設定できるようにする必要があります。 (Railsの認証プラグインの最も単純な形式では、通常、最初の種類のロールのみを定義し、ユーザーに対して1つのロールのみを設定できます。)
承認のもう1つの部分は、ユーザーが何らかのロール(ロールのセット)に適合するかどうかに基づいて、コードのどの部分を実行する(または実行しない)かを決定するメカニズムです。このメカニズムを適用するには、承認を行うポイントを見つけて、コードを実行するまたは実行しないロールを選択する必要があります。
Railsで私のために働く方法は、モデルレベルでロールを定義し、承認メカニズムを終了することです(承認したいコードの部分に許可されたロールを設定し、現在のユーザーに許可されているロールがあるかどうかを尋ねるコントローラー/ビューのために完全にパーツを実行します。
このために、先ほど述べたすべての可能性が組み込まれた調整済みのrails-authorization-pluginを使用します(さまざまな種類のロール、1人のユーザーの多くのロール、コントローラーおよびビューレベルの承認)。
他のヒント
アクセスのためのコントロールポイントとして、モデルに「機能ポイント」または「機能」の概念を導入する必要がある場合があります。 「機能」には、階層を形成するためのオプションの「親機能」があります。機能の有無を決定し、プログラムでアクセス許可を確認します。これにより、メニューを描画する前に機能レベルのアクセスを確認できるようになり、ユーザーがアクセスを許可されていないページへのリンクが表示されなくなります。
同様の状況/解決策が説明されていますここ
2つの提案のうち、最初のオプションは、モデルレベルのアクションではない可能性のあるアクションを追加できるため、少し改善されています。 2番目のモデルでは十分ではないケースに出くわすと思います。スキーマを変更するか、アプリ全体に許可ロジックを振りかける必要があります(例:" 'create'のないユーザーアクセスもメソッドxxx")を実行できません
ソリューションがあまりドライに見えない理由は、繰り返しがあるからだと思います:
- 部門名、および
- 部門の機能内
#1に関しては、departmentsテーブルを作成し、各部門にIDを与えることは理にかなっています。
#2に関しては、最初のコメントに同意します。おそらく、さまざまなコントローラーとアクションを機能グループにクラスター化してから、ユーザーと機能の間に多対多の関係(マッピングテーブル)を設定できます。その場合、関数は許可するアクション/コントローラーと1対多の関係になります。これにより、最小限の繰り返しで、「会計と販売はすべての財務テーブルを読み取ることができるはずです」と言うことができます。