Concept de structure...

tabasco_nemesis Messages postés 11 Date d'inscription samedi 22 juillet 2006 Statut Membre Dernière intervention 23 novembre 2011 - 27 nov. 2009 à 16:32
tabasco_nemesis Messages postés 11 Date d'inscription samedi 22 juillet 2006 Statut Membre Dernière intervention 23 novembre 2011 - 2 déc. 2009 à 13:48
Bonjour à tous.
Je suis en train de réaliser un "framework" perso : pour comprendre, et pour savoir quoi faire et où et comment lorsque je suis amené à créer un site par exemple. Je ne suis pas développeur "Pro" mais je me débrouille un peu en POO (merci Malalam et autres Boss :-) vos tutos et messages ce sont des mines d'infos !).

Je vous décrit d'abord mon "principe" (je ne sais pas comment formuler ça autrement), et après je vous poserais la question.

Dans mon "framework", il y a deux partie : l'interface de gestion des éléments (aucun interêt ici) et un "système" (et c'est la-dedans que c'est important.

Outre des outils (classes, fonctions... pour traiter les insertion BDD, les e-mails, le template, des logs etc...), il y a la partie principale : les utilisateurs, et les ressources.

Les utilisateurs :
Il y a une table User(id_user, fk_id_group, username, etc...),
Une table Group(id_group, id_parent_group, label, id_admin_group, etc...),
Une table Rules(id_rule, label, description, etc...)
Une table Permission(fk_id_rule, fk_id_Group)

Quand un utilisateur se logge, on génère plusieurs tableaux (que j'ai mis dans une $_SESSION[ACL]).
Le premier, pour la lecture, contient le groupe de l'utilisateur et tous les groupes-enfant (par table.Group(id_group, id_parent_group), plus le zéro pour n'importe quel groupe existant, plus le moins 1 (-1), pour "tout". ex: array('-1', '0', '3', '5', '6'), ou false si c'est un utilisateur non référencé (non loggé en fait).
Le second pour l'écriture, c'est identique, mais on part sur (table.Group(id_admin_Group, id_parent)). ex: array('3', '5', '6') pour un utilisateur Administrateur du groupe 3 (qui à les groupes 5 et 6 en enfant), ou False si ce n'est pas un administrateur de groupe
Le troisième, pour les Permissions, est la liste de toutes les Rules et True ou False en fonction de la table.Permission. ex: array('edit_user'=>true, 'edit_config'=>false, 'edit_document'=>true

Ensuite, les "ressources" (par exemple Document (ou alors un produit, un port-folio, etc...)
table.Document(id, date, etc..., id_owner, access) ou 'id_owner' est l'id_user' du créateur/propriétaire, et 'access' l'id_group' pour le niveau de partage/diffusion.

Je traite alors lorsqu'un utilisateur souhaite accéder en lecture à un document d'abord $_SESSION['ACL']['Permissions'] est vrai, ensuite si le groupe du propriétaire (via id_owner) est dans la liste $_SESSION['ACL']['Read'] et si non, je test dans la liste $_SESSION['ACL']['Write'] (si c'est un administrateur de groupe donc).
Si c'est pour passer en mode "édition", je fait les Persmissions, et le Write uniquement.

Dans mes objets (User et Group par exemple) new User($id), sur la fonction de chargement des propriétés, dans la requete via PDO SELECT * FROM tabel.user WHERE id = $id AND id_group IN ('ma', 'liste', 'tirée, 'de', 'ACLRead') et sur la fonction d'écriture, je teste 'Permissions' et id_group in_array(ACLWrite) avant d'exécuter la requete.

Bien sûr, toutes les données sont testé avant d'exécuter les requetes (type int, string, échappement, htmlentities, etc...)

Alors voilà la question (enfin !).
Le principe est-il bon ? Je veux dire la modélisation des tables, les différents tableaux, l'utilisation de ces résultats.
Le but étant d'avoir une bonne base où l'on peu ajouter des groupes, des sous-groupes, d'autre ressources, et des régles.
Y-a-t-il des points à vérifier avec attention qui risqueraient de créer des problèmes. Et de quel genre...
Bonne logique ?

Merci d'avance.

2 réponses

neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
30 nov. 2009 à 20:37
Salut,

J'ai tout lu (sisi, véridique). J'ai même tout compris, enfin je pense. J'ai pas réfléchi en détails, mais l'idée ne me parait pas mauvaise.
Ta question, tu dois pouvoir y répondre tout seul, si tu fais un peu l'analyse de ce dont tu as besoin au départ : les fonctionnalités à implémenter, comment décrire chaque objet (user en l'occurrence).

Tel que je vois tes tables, un utilisateur peut faire partie au maximum d'un groupe. Personnellement, j'ai tendance à toujours permettre qu'un utilisateur soit dans plusieurs groupes. Ca donne une relation n,n entre les tables users et groups, il faut donc une table supplémentaire qui matérialise cette relation conceptuelle.

Tu donnes des noms différents à tes clé étrangères en les préfixant avec fk_ : c'est, d'un point de vue conceptuel, mauvais. Une clé étrangère n'est que la manifestation de la relation entre deux tables, par une donnée. Cette donnée est la même dans les deux tables. Il FAUT donc l'appeler toujours pareil. Par contre, il faut TOUJOURS utiliser des noms différents pour des données différentes. Par exemple, je vois souvent des bases de données avec plusieurs données qui portent le nom "name", ou "address" : un coup il s'agit du nom d'un utilisateur, un coup du nom d'un film, une autre fois de celui d'un animal de comapgnie, ...
Par contre id_rule et fk_id_rule sont strictement la même donnée, il faut donc nommer les champs de manière identique.
Je sais : ça ne change pas le fonctionnement. Mais conceptuellement, ce n'est pas du tout la même chose. Quand on établi un dictionnaire de données, chaque donnée est identifiée par son nom : la retrouver plusieurs fois avec plusieurs noms est une erreur. De même, ne trouver qu'un nom pour représenter plusieurs données différentes est aussi une erreur.

Ta manière de gérer les permissions simple utilisateur et admin me paraît limitative. Si je comprends bien, tu utilises la permission d'écriture comme identifiant un admin, donc autorisant l'accès en lecture. Ca ne te laisse pas beaucoup de marge de manoeuvre si tu souhaites changer la hiérarchie des groupes ou des permissions.

La gestion des permissions est une problèmatique cruciale sur un site, d'autant plus s'il s'agit d'un site communautaire ou basé sur l'UGC (User Generated Content, comme un wiki, un blog collectif, etc). Il est possible de gérer cette problématique de plusieurs manières, mais il n'est pas forcément bon de les mélanger : si on y gagne en souplesse dans la théorie, dans l'utilisation, on peut vite s'emmêler les pinceaux (comme avec les permissions de phpBB2, c'était un grand n'importe quoi).

Ma manière de voir est d'utiliser des groupes, et uniquement des groupes. Si on souhaite donner des permissions très précises à un utilisateur en particulier, il suffit de lui dédier un groupe. On peut donc avoir au maximum autant de groupes que d'utilisateurs + les groupes "normaux". Il est donc important, dans cette optique, de permettre à un utilisateur de faire partie de plusieurs groupes, sachant que si l'appartenance à un groupe donne la permission, alors l'utilisateur a la permission. Pour les cas des utilisateurs punis, il suffit de les enlever des groupes auxquels ils appartiennent et de les ranger dans un groupe spécifique, avec des permissions limitées. On peut aussi, si on ne souhaite pas effacer les groupes (et donc les permissions) actuelles, gérer spécifiquement les permissions de ce groupe limité (alors, on ne tient compte que des permissions de ce groupe).

Ceci étant dit, voici comment j'implémenterais ça :
table users (user_id, user_login, user_password, etc)
table groups (group_id, group_name, etc)
table users_groups (user_id, group_id)
table rules (rule_id, rule_name)
table permissions (group_id, rule_id)

Pour les tables users et groups, pas besoin d'explications... La table users_groups permet à la relation n,n entre les tables users et groups d'exister.
La table rules liste les permissions que tu souhaites octroyer sur ton site : lecture, création, modification, suppression, bannir un membre, etc. Rien de plus.
La table acl définit les permissions qui sont DONNEES à un groupe. Si la relation group-rule n'existe pas, alors le groupe n'a pas la permission d'exécuter cette action.
Pour les membres punis qui feraient partie d'un groupe limité, il conviendrait alors de ne vérifier les permissions QUE pour ce groupe, pas pour les autres.

Concrètement, pour connaître les permissions d'un utilisateur :
SELECT r.rule_name
FROM rules r
LEFT JOIN permissions p ON p.rule_id = r.rule_id
LEFT JOIN users_groups ug ON ug.group_id=p.group_id
LEFT JOIN groups g ON ug.group_id = g.group_id
WHERE ug.user_id = 2


Question optimisation, je n'ai aucune idée de ce que ça donne, par contre ^^ Ca s'exécute rapidement chez moi, mais comme j'ai mis que 2 groupes, 2 utilisateurs, 4 permissions...
Par contre, c'est ce que je vois de mieux en terme de flexibilité. En plus, là, c'est MySQL qui calcule tout seul si l'utilisateur a la permissions ou pas. Si la permission sort sur une ligne, c'est que oui, sinon, non. Un simple isset() sur un tableau associatif permet de connaître la permission.

Je sais pas si ça répond à ta question, mais c'est quand même ce que je réponds ^^

--
Neige

Souvent la réponse à votre question se trouve dans la doc. Commencez par là ;)
0
tabasco_nemesis Messages postés 11 Date d'inscription samedi 22 juillet 2006 Statut Membre Dernière intervention 23 novembre 2011
2 déc. 2009 à 13:48
Bonjour Neigedhiver.

Je te crois : tu as tout lu :-)
Ta réponse très clair et dans le "total context" de mon besoin me donne des clés !
Je vais de suite tester cette méthode. Elle me semble idéale pour mon projet.

En plus, pour l'optimisation (et Mysql), mes "applications" sont à "faible charge" : il est peu probable de dépasser les 1000 visiteurs par jour, et de plus pour la plupart, ce sera de la consultation "publique", alors je peux trouver une astuce pour réduire les requêtes d'autorisation.

ET je reviendrais avec des questions sur mes classes et la manière dont j'implémente l'utilisation de ce système de droit.

Merci.
Je suis encore ouvert à tous conseils et avis.
0
Rejoignez-nous