Menyimpan item menu dengan izin pengguna


11

Saya membuat sistem menu di PHP dan MySQL. Saya akan memiliki beberapa menu berbeda dan setiap menu akan memiliki satu set item menu yang terhubung dengannya.

Di situs itu, saya juga memiliki izin pengguna yang berbeda, beberapa pengguna dapat melihat semua item menu dan beberapa item disembunyikan dari beberapa pengguna. Saya ingin tahu tentang bagaimana saya bisa menangani izin dengan cara bersih yang akan memungkinkan lebih banyak jenis pengguna di masa depan dengan mudah ditambahkan.

Apa yang saya miliki sejauh ini adalah sesuatu seperti ini:

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

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

Saya berpikir bahwa permissionkolom dapat berupa string yang dipisahkan koma yang dapat saya cocokkan dengan id izin pengguna saat ini. Itu juga bisa menjadi referensi ke beberapa tabel lain yang mendefinisikan semua kemungkinan kombinasi dari izin yang ada saat ini.

Salah satu solusi juga bisa dengan hanya menyimpan beberapa item menu di mana satu-satunya perbedaan adalah izin meskipun ini akan menyebabkan penyimpanan duplikat dan mungkin menyulitkan untuk mengelola.

Saya ingin mendengar beberapa pemikiran tentang bagaimana menyusun ini dan apa yang bisa dianggap bersih, dinamis, dan jelek.

Terima kasih.


Apakah pengguna memiliki kesamaan? Biasanya Anda akan mengelompokkan item menu ke dalam grup fungsional dan menetapkan pengguna ke grup tersebut (misalnya - pengguna Admin, pengguna DB, pedagang, dll.). Kemudian Anda hanya mengatur pengelompokan, tergantung pada pilihan teknologi - ini dapat dikelola dengan menggunakan sesuatu seperti Active Directory.
Michael

1
Anda mendapatkan banyak jawaban bagus di sini, tetapi yang mungkin ingin Anda baca adalah ACL. en.wikipedia.org/wiki/Access_control_list
Reactgular

Jawaban:


17

Saya akan memodelkannya menggunakan diagram ER.

  • A PERMISSIONadalah akses yang diberikan pada ROLEpada yang diberikan MENU_ITEM.
  • ROLE adalah seperangkat izin yang telah ditentukan sebelumnya yang diberi nama
  • A USERdapat memiliki banyak ROLE yang diberikan padanya.
  • Memiliki izin yang ditetapkan untuk peran alih-alih pengguna, membuat administrasi izin lebih mudah.

masukkan deskripsi gambar di sini

Kemudian Anda dapat membuat tampilan sehingga Anda tidak perlu menulis gabungan setiap kali:

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)

Kemudian setiap kali Anda ingin tahu item menu apa yang dapat diakses oleh pengguna, Anda dapat menanyakannya:

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

EDIT:

Karena pengguna dapat memiliki beberapa peran yang diberikan, izin peran dapat tumpang tindih, yaitu dua peran yang berbeda dapat memiliki akses ke item menu yang sama. Saat Anda menentukan peran, Anda tidak tahu sebelumnya apakah itu akan memiliki beberapa izin yang sama dengan peran lainnya. Tapi karena ini tentang penyatuan set, itu hanya masalah apakah izin yang diberikan adalah bagian dari set, bukan berapa kali muncul, maka distinctklausa dalam tampilan.


Keren terima kasih. Tidak bisa melihat mengapa saya tidak bisa menggambarkannya sendiri. Kira saya diblokir dan tidak berpengalaman :)
span

Ack, saya pikir saya mengerti tetapi jelas tidak mengerti. Bagaimana saya bisa memiliki beberapa izin untuk satu item menu?
span

1
@span Karena pengguna dapat memiliki beberapa peran yang diberikan dan izin peran dapat tumpang tindih, yaitu dua peran yang berbeda dapat memiliki akses ke item menu yang sama. Saat Anda menentukan peran, Anda tidak tahu sebelumnya apakah peran tersebut akan diberikan bersama dengan yang lain yang memiliki beberapa izin yang sama dengannya. Tapi karena masalah ini adalah tentang penyatuan set, itu hanya masalah apakah izin yang diberikan adalah bagian dari set atau tidak, bukan berapa kali muncul.
Tulains Córdova

Terima kasih, saya akan terus membaca jawaban Anda sampai saya mendapatkannya;). Saya pikir kesalahan saya adalah berpikir bahwa satu izin dapat digunakan bersama dengan peran untuk memisahkan item menu. Sepertinya saya perlu izin untuk setiap 'jenis' item menu. Sekali lagi, terima kasih atas bantuan Anda! Saya akan menggambar beberapa diagram Venn dan melihat apakah saya dapat mengatasinya dengan benar \ o /
span

5

Memiliki daftar yang dipisahkan koma berarti melakukan perbandingan substring setiap kali Anda melakukan kueri terhadap menu. Ini kurang ideal.

Anda perlu menormalkan tabel:

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

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

Jika Anda masih menginginkan daftar yang dipisahkan koma (karena alasan tertentu), Anda dapat menariknya dengan hal-hal seperti group_concatdi mysql wm_concat di oracle atau fungsi serupa dalam bahasa lain.

Keuntungan untuk ini adalah multi-lipat.

Pertama, ada kepraktisan panggilan itu. Melakukan substring terhadap string sewenang-wenang besar (jika Anda memperbaiki ukuran itu, Anda dapat memiliki masalah di kemudian hari dengan mengisi string sehingga Anda mulai mendapatkan izin seperti abukan another_permission) berarti pemindaian string pada setiap baris. Ini bukan sesuatu yang dioptimalisasi oleh basis data.

Kedua, kueri yang Anda tulis menjadi lebih sederhana. Untuk menentukan apakah izin 'foo' ada dalam daftar yang dipisahkan koma, Anda perlu memeriksa 'foo'.

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

Namun, ini akan memberikan false positive jika Anda juga memiliki izin 'foobar'. Jadi sekarang Anda perlu melakukan tes seperti

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

tetapi itu akan memberikan negatif palsu jika 'foo' ada di awal atau di akhir string. Itu mengarah ke sesuatu seperti

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

Anda akan mencatat bahwa sangat mungkin Anda perlu melakukan beberapa pemindaian string. Cara ini menyebabkan kegilaan.

Catatan dengan semua ini Anda tidak memiliki kemampuan praktis untuk melakukan pengikatan parameter (masih mungkin, hanya saja semakin jelek).

Normalisasi bidang memberi Anda fleksibilitas dan keterbacaan yang jauh lebih besar dalam database Anda. Anda tidak akan menyesalinya.


Terima kasih atas jawaban Anda yang luar biasa, itu telah memberi saya lebih banyak pengetahuan dan saya bersyukur untuk itu meskipun saya pikir solusi user61852 akan cocok untuk saat ini.
span

3

Bahwa pendekatan klasik untuk ini User -> UserGroupdan kemudian dikaitkan a Menu -> MenuItem -> UserGroup. Menggunakan nilai integer untuk menimbang tingkat izin.

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

Ketika Anda perlu menampilkan menu untuk pengguna saat ini. Anda dapat meminta basis data seperti ini.

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

Itu hanya akan memilih menu yang terlihat oleh pengguna saat ini berdasarkan kondisi untuk option1.

Atau, jika Anda menyimpan detail grup pengguna saat ini di sesi saat ini, maka tidak diperlukan bergabung.

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

Ketika Anda berbicara tentang keinginan untuk menyimpan beberapa izin per item menu. Saya akan berhati-hati untuk tidak membingungkan peran pengguna dan logika bisnis.


2
Desain ini hanya akan memungkinkan setiap MenuItem untuk diikat ke UserGroup tunggal, yang berarti baik menu terbatas atau duplikasi data. Sebenarnya Anda menginginkan tabel tautan, idealnya. Juga, pilihan Anda untuk penamaan tabel DB sebagai bentuk jamak membuat saya sedih;)
Ed James

@ Edwoodcock oh poin yang sangat bagus. Saya seharusnya pergi dengan tingkat izin (int) dan kemudian membandingkannya dengan tingkat grup pengguna. Saya akan mengubahnya. Perhatikan, kebiasaan nama jamak yang disebabkan oleh penggunaan CakePHP oleh saya. Yang aneh, menyebabkan kerangka kerja menggunakan alias tunggal untuk tabel dalam kueri.
Reactgular

@MatthewFoscarini Jangan khawatir, saya tidak benar-benar peduli selama basis kode konsisten;)
Ed James

1
Jawaban yang luar biasa. Saya akan mengingat hal ini lain kali jika saya melakukan sesuatu seperti ini. Untuk saat ini saya pikir solusi user61852 akan paling cocok karena tidak memerlukan banyak perubahan pada kode yang ada. Terima kasih!
span
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.