ユーザー権限を持つメニュー項目の保存


11

PHPとMySQLでメニューシステムを作成しています。いくつかの異なるメニューを用意し、各メニューに一連のメニュー項目を接続します。

サイトでは、別のユーザー権限も持っています。一部のユーザーはすべてのメニューアイテムを表示でき、一部のアイテムは一部のユーザーから非表示になっています。将来、より多くの種類のユーザーを簡単に追加できるように、権限をクリーンな方法で処理する方法に興味があります。

これまでのところ、次のようなものです。

-------------------
|Menus
-------------------
|id| |display name|
-------------------

----------------------------------------------------------
|Menu items
----------------------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort| |permission|
----------------------------------------------------------

permission列は、現在のユーザーのアクセス許可IDと照合できるコンマ区切りの文字列のいずれかであると考えています。また、現在存在する権限のすべての可能な組み合わせを定義する他のいくつかのテーブルへの参照である可能性もあります。

1つの解決策は、複数のメニュー項目を単純に格納することでもありますが、唯一の違いは許可ですが、これはストレージの重複を引き起こし、おそらく管理が面倒になります。

これをどのように構成するか、そしてクリーンでダイナミックで無愛想なものと見なすことができるものについての考えを聞いてみたいです。

ありがとう。


ユーザーに共通点はありますか?通常、メニュー項目を機能グループにグループ化し、それらのグループにユーザーを割り当てます(たとえば、管理ユーザー、DBユーザー、トレーダーなど)。次に、テクノロジーの選択に応じて、グループ化を管理します。これは、Active Directoryなどを使用して管理できます。
マイケル

1
あなたはここで多くの良い答えを得ていますが、あなたが読みたいのはACLです。en.wikipedia.org/wiki/Access_control_list
Reactgular 2013

回答:


17

ER図を使ってモデル化します。

  • A PERMISSIONは、ROLE特定のでに付与されるアクセスMENU_ITEMです。
  • ROLEは、名前が付けられた事前定義された権限のセットです
  • AにUSERは多くのROLEを付与できます。
  • ユーザーではなくロールに権限を割り当てると、権限の管理がはるかに簡単になります。

ここに画像の説明を入力してください

次に、ビューを作成して、毎回結合を記述する必要がないようにします。

create or replace view v_user_permissions
select
    distinct mi.id, mi.menu_id. mi.label. mi.link, mi.parent, mi.sort, u.user_id
from
    user u
    join user_role ur on (u.user_id = ur.user_id)
    join role ro on (ur.role_id = role.role_id)
    join permission per on (ro.role_id = per.role_id)
    join menu_item mi on (per.metu_item_id = mi.metu_item_id)

次に、ユーザーがアクセスできるメニュー項目を知りたいときはいつでも、それを照会できます。

select * from v_user_permissions up where up.user_id = 12736 order by up.sort

編集:

ユーザーは複数のロールを付与できるため、ロールの権限が重複する可能性があります。つまり、2つの異なるロールが同じメニュー項目にアクセスできます。ロールを定義するとき、他のロールと共通の権限を持つかどうかは事前にわかりません。しかし、それはセットの結合に関するものであるため、特定の許可がセットの一部であるかどうかだけが重要であり、それが出現する回数ではなく、したがってdistinctビュー内の節が重要です。


素晴らしいです、ありがとう。自分でそれを作成できなかった理由がわかりません。私がブロックされた推測と非経験豊富な:)
スパン

了解しました。理解できたと思いましたが、明らかにわかりませんでした。単一のメニュー項目に複数の権限を与えるにはどうすればよいですか?
2013

1
@spanユーザーには複数の役割を付与でき、役割の権限を重複させることができるため、2つの異なる役割が同じメニュー項目にアクセスできます。ロールを定義するとき、そのロールがいくつかの共通の権限を持つ他のロールとともに付与されるかどうかは、事前にわかりません。ただし、この問題はセットの結合に関するものであるため、特定の権限がセットの一部であるかどうかだけが重要であり、何回現れるかは問題ではありません。
TulainsCórdova13年

おかげで、私はそれを得るまであなたの答えを読み続けます;)。私の間違いは、単一の許可をメニュー項目を分離する役割と一緒に使用できると考えることにあったと思います。メニュー項目の「タイプ」ごとに許可が必要なようです。もう一度、あなたの助けに感謝します!私はいくつかのベン図を描き、私はきちんと\ O /それのまわりで私の頭を取得することができるかどうかがわかります
スパン

5

コンマで区切られたリストを持つことは、メニューに対してクエリを実行するたびに部分文字列の比較を行うことを意味します。これは理想的ではありません。

テーブルを正規化する必要があります:

---------------------------------------------
|Menu items
---------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort|
---------------------------------------------

+---------------------------+
| menu_permission           |
|---------------------------|
| |menu_permission_id| (pk) |
| |menu_id| (fk)            |
| |permission|              |
+---------------------------+

(何らかの理由で)コンマ区切りのリストが引き続き必要な場合は、Oracleのmysqlや他の言語の同様の関数などを使用group_concatしてリストを引き出すことができます。 wm_concat

これの利点は多面的です。

最初に、呼び出しの実用性があります。任意の大きさの文字列に対する部分文字列をやって(あなたのサイズそれを修正する場合は、同様の許可取得を開始して、後で文字列を埋めると上の問題を持つことができますa代わりのをanother_permission)各行の文字列をスキャンする手段。これはデータベースが最適化されているものではありません。

第二に、あなたが書くクエリははるかに簡単になります。許可「foo」がコンマ区切りのリストに存在するかどうかを判別するには、「foo」を確認する必要があります。

... permission like "%foo%" ...

ただし、「foobar」権限も持っている場合は、誤検知が発生します。だから今あなたはのようなテストをする必要があります

... permission like "%,foo,%" ...

ただし、「foo」が文字列の先頭または末尾にある場合は、偽陰性になります。それは次のようなものにつながります

... (permission like "foo,%" 
  or permission like "%,foo,%" 
  or permission like "%,foo" ) ...

文字列を複数回スキャンする必要がある可能性が高いことに注意してください。この方法は狂気につながります。

これらすべてでは、パラメーターバインディングを実行する実用的な機能が不足していることに注意してください(まだ可能ですが、さらに醜くなります)。

フィールドを正規化すると、データベースの柔軟性と可読性が大幅に向上します。後悔はしません。


あなたの素晴らしい答えをありがとう、それは私に多くの知識を与えてくれました、そして私はuser61852ソリューションが今のところ最も適していると思いますが私はそれについて素晴らしいです。
2013

3

これに対するその古典的なアプローチはUser -> UserGroup、と関連付けられていMenu -> MenuItem -> UserGroupます。整数値を使用してアクセス許可レベルを比較検討します。

-------------------
|Menu
-------------------
|id| |display name|
-------------------

-------------------------------------------------------------
|Menu Item
-------------------------------------------------------------
|id| |menu_id| |label| |link| |parent| |sort| | min_option1
-------------------------------------------------------------

-------------------------------------------
| User
-------------------------------------------
|id| | username | password | user_group_id
-------------------------------------------

-------------------------------------------
| User Group
-------------------------------------------
|id| option1 | option2 | option2
-------------------------------------------

現在のユーザーのメニューを表示する必要がある場合。このようにしてデータベースをクエリできます。

SELECT * FROM `MenuItem`
    LEFT JOIN `UserGroup` ON (`MenuItem`.`user_group_id` = `UserGroup`.`id`)
    LEFT JOIN `User` ON (`UserGroup`.`id` = `User`.`user_group_id` AND `User`.`id` = $current_user_id)
        WHERE `MenuItem`.`menu_id` = $menu_id AND `UserGroup`.`option1` >= `MenuItem`.`min_option1`;

これは、の条件に基づいて現在のユーザーに表示されるメニューのみを選択しますoption1

または、現在のユーザーのグループの詳細を現在のセッションに保存する場合、参加は必要ありません。

SELECT * FROM `MenuItem` WHERE `MenuItem`.`menu_id` = $menu_id AND `MenuItem`.`min_option1` >= $user_group_option1;

メニュー項目ごとに複数の権限を保存したい場合。ユーザーの役割とビジネスロジックを混同しないように注意します。


2
この設計では、各MenuItemを単一のUserGroupにのみ関連付けることができます。つまり、メニューが制限されているか、データが重複しています。実際には、リンクテーブルが理想的です。また、DBテーブルの名前を複数形として選択すると、私は悲しくなります;)
Ed James

@EdWoodcock非常に良い点です。私はアクセス許可レベル(int)を使用して、それをユーザーのグループレベルと比較する必要がありました。それを変えます。私がCakePHPを使用したことにより、複数の名前が習慣化されていることに注意してください。奇妙なことですが、フレームワークはクエリのテーブルに単一のエイリアスを使用します。
Reactgular 2013

@MatthewFoscarini心配ありません。コードベースが一貫している限り、私は本当に気になりません;)
Ed James

1
素晴らしい答え。これを好きなことをするときは、これを覚えておきます。今のところ、既存のコードに多くの変更を加える必要がないため、user61852ソリューションが最適だと思います。ありがとう!
スパン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.