Menü öğelerini kullanıcı izinleriyle saklama


11

PHP ve MySQL'de bir menü sistemi oluşturuyorum. Birkaç farklı menüye sahip olacağım ve her menünün kendisine bağlı bir dizi menü öğesi olacak.

Sitede ayrıca farklı kullanıcı izinlerim var, bazı kullanıcılar tüm menü öğelerini görebilir ve bazı öğeler bazı kullanıcılardan gizlenir. Gelecekte daha fazla kullanıcının kolayca eklenmesini sağlayacak izinleri temiz bir şekilde nasıl ele alabileceğimi merak ediyorum.

Şimdiye kadar sahip olduğum şey şudur:

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

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

permissionSütun, geçerli kullanıcının izin kimliği ile eşleşebilecek virgülle ayrılmış bir dize olabileceğini düşünüyorum . Ayrıca, varolan izinlerin olası tüm birleşimlerini tanımlayan başka bir tabloya da başvuru olabilir.

Bir çözüm aynı zamanda birden fazla menü öğesini saklamak olabilir, ancak tek fark izintir, ancak bu yinelenen depolamaya ve belki de yönetmek için bir acıya yol açacaktır.

Bunu nasıl yapılandıracağımız ve neyin temiz, dinamik ve berbat olduğu düşünülebilir.

Teşekkürler.


Kullanıcıların ortak bir yanı var mı? Genellikle menü öğelerini işlevsel gruplara gruplandırır ve kullanıcıları bu gruplara atarsınız (örneğin - Yönetici kullanıcılar, DB kullanıcıları, tüccarlar vb.). Ardından, teknoloji seçimine bağlı olarak gruplamaları yönetirsiniz - bu, Active Directory gibi bir şey kullanılarak yönetilebilir.
Michael

1
Burada birçok iyi yanıt alıyorsunuz, ancak okumak isteyebileceğiniz şey ACL. en.wikipedia.org/wiki/Access_control_list
Reactgular

Yanıtlar:


18

Bir ER diyagramı kullanarak modelleyeceğim.

  • A PERMISSION, ROLEbelirli bir kişiye verilen erişimdir MENU_ITEM.
  • ROLE, bir ad verilen önceden tanımlanmış izinler kümesidir
  • A USER, kendisine birçok ROL verebilir.
  • Kullanıcıların yerine rollere atanmış izinlere sahip olmak, izinlerin yönetimini çok daha kolay hale getirir.

resim açıklamasını buraya girin

Ardından bir görünüm oluşturabilirsiniz, böylece birleştirmeleri her seferinde yazmak zorunda kalmazsınız:

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)

Ardından, bir kullanıcının hangi menü öğelerine erişebileceğini her bilmek istediğinizde, bunu sorgulayabilirsiniz:

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

DÜZENLE:

Bir kullanıcıya birden fazla rol verilebildiğinden, rollerin izinleri çakışabilir, yani iki ayrı rol aynı menü öğesine erişebilir. Önceden bilmediğiniz bir rolü tanımladığınızda, diğer rollerle bazı ortak izinleri olup olmayacağını önceden bilmezsiniz. Ancak bu, kümelerin birliği ile ilgili olduğu için, verilen bir iznin kümenin bir parçası olup olmadığı, kaç kez göründüğü değil, dolayısıyla distinctgörünümdeki madde ile ilgilidir.


Harika, teşekkürler. Bunu neden kendim çizemediğimi göremiyorum. Sanırım engellendim ve tecrübesiz :)
span

Ack, anladığımı düşündüm ama belli ki anlamadım. Tek bir menü öğesi için birden çok izne nasıl sahip olabilirim?
span

1
@span Bir kullanıcıya birden fazla rol verilebildiği ve rollerin izinleri çakışabileceği için, aynı menü öğesine iki ayrı rol erişebilir. Bir rol tanımladığınızda, rolün ortak bazı izinleri olan diğer rollerle birlikte verilip verilmeyeceğini önceden bilmiyorsunuzdur. Ancak bu sorun kümelerin birleşmesi ile ilgili olduğundan, sadece verilen bir iznin kümenin bir parçası olup olmadığı, kaç kez göründüğü önemli değildir.
Tulains Córdova

Teşekkürler, cevap alana kadar cevap vermeye devam edeceğim;). Sanırım hatam, menü öğelerini ayırma rolü ile birlikte tek bir iznin kullanılabileceğini düşünmektir. Menü öğesinin her 'türü' için bir izne ihtiyacım var gibi görünüyor. Yardımlarınız için bir kez daha teşekkürler! Bazı Venn şemaları çizeceğim ve kafamı düzgün bir şekilde bulabileceğimi göreceğim \ o /
span

5

Virgülle ayrılmış bir listeye sahip olmak, menüye karşı her sorgu yaptığınızda bir alt dize karşılaştırması yapmak anlamına gelir. Bu ideal olandan daha az.

Tabloyu normalleştirmeniz gerekir:

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

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

Hala (nedense) virgülle ayrılmış liste istiyorsanız, gibi şeylerle onu çıkarır group_concatiçinde mysql wm_concat içinde torpil diğer dillerde veya benzer işlevlere.

Bunun avantajı çok katlıdır.

İlk olarak, çağrının pratikliği var. İsteğe bağlı olarak büyük bir dizeye karşı bir alt dize yapmak (boyutu düzeltirseniz, daha sonra dizeyi doldurmayla ilgili sorunlar yaşayabilirsiniz, böylece ayerine izin almaya başlayabilirsiniz another_permission), her satırdaki dizeyi taramak anlamına gelir. Bu veritabanlarının istediği bir şey değil.

İkinci olarak, yazdığınız sorgu çok daha basit hale gelir. 'Foo' izninin virgülle ayrılmış bir listede olup olmadığını belirlemek için 'foo'yu kontrol etmeniz gerekir.

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

Bununla birlikte, eğer 'foobar' iznine sahipseniz, bu yanlış bir pozitif verecektir. Şimdi bir teste ihtiyacınız var.

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

ancak 'foo' dizenin başında veya sonundaysa bu yanlış negatif verir. Bu gibi bir şeye yol açar

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

Dizenin birden çok taramasını yapmanızın büyük olasılıkla olduğunu göreceksiniz. Bu şekilde deliliğe yol açar.

Tüm bunlarla birlikte, parametre bağlaması yapmak için pratik yeteneğe sahip olmadığınızı unutmayın (yine de mümkün, sadece daha çirkinleşiyor).

Alanı normalleştirmek veritabanınızda çok daha fazla esneklik ve okunabilirlik sağlar. Pişman olmayacaksınız.


Müthiş cevabınız için teşekkür ederim, bana daha fazla bilgi verdi ve bunun için mükemmelim, ancak user61852 çözümünün şimdilik en uygun olacağını düşünüyorum.
span

3

Bu klasik yaklaşım User -> UserGroupve sonra a Menu -> MenuItem -> UserGroup. İzin düzeyini tartmak için bir tamsayı değeri kullanma.

-------------------
|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
-------------------------------------------

Geçerli kullanıcı için bir menü görüntülemeniz gerektiğinde. Veritabanını böyle sorgulayabilirsiniz.

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`;

Bu, yalnızca koşula bağlı olarak geçerli kullanıcı tarafından görülebilen menüleri seçer option1.

Alternatif olarak, geçerli kullanıcının grup ayrıntılarını geçerli oturumda depolarsanız, birleştirmeye gerek yoktur.

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

Menü öğesi başına birden fazla izin saklamak istediğinizden bahsettiğinizde. Kullanıcı rollerini ve iş mantığını karıştırmamaya dikkat ediyorum.


2
Bu tasarım, her MenuItem öğesinin tek bir UserGroup'a bağlanmasına izin verir, yani sınırlı menüler veya veri çoğaltma anlamına gelir. Gerçekte ideal olarak bir bağlantı tablosu istiyorsunuz. Ayrıca, çoğul olarak DB tablo adlandırma seçtiğiniz beni üzüyor;)
Ed James

@EdWoodcock oh çok iyi bir nokta. Bir izin düzeyine (int) gitmeli ve bunu kullanıcının grup düzeyiyle karşılaştırmalıydım. Bunu değiştireceğim. Not, CakePHP kullanmamın neden olduğu çoğul isimler alışkanlığı. Garip olan, çerçevenin sorgulardaki tablolar için tekil takma adlar kullanmasına neden olur.
Reactgular

@MatthewFoscarini Endişelenmeyin, bir kod tabanı tutarlı olduğu sürece gerçekten rahatsız değilim;)
Ed James

1
Müthiş cevap. Bunu sevdiğim bir dahaki sefere bunu aklımda tutacağım. Şimdilik, mevcut kodda çok fazla değişiklik gerektirmediği için user61852 çözümünün en uygun olacağını düşünüyorum. Teşekkürler!
span
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.