Nella mia esperienza, la vera domanda si riduce principalmente al fatto che si verificherà o meno una quantità di restrizione di accesso specifica per l'utente.
Supponiamo, ad esempio, di progettare lo schema di una community e di consentire agli utenti di attivare o disattivare la visibilità del loro profilo.
Un'opzione è attenersi a un flag di profilo pubblico/privato e attenersi a controlli di autorizzazione ampi e preventivi:"users.view" (visualizza utenti pubblici) vs, ad esempio, "users.view_all" (visualizza tutti gli utenti, per i moderatori) .
Un altro riguarda autorizzazioni più raffinate, potresti volere che siano in grado di configurare le cose in modo che possano rendersi (a) visibili a tutti, (b) visibili dai loro amici selezionati, (c) mantenute completamente private e forse (d ) visibili a tutti tranne che ai loro bozos selezionati a mano. In questo caso è necessario memorizzare i dati relativi al proprietario/all'accesso per singole righe e sarà necessario astrarre pesantemente alcune di queste cose per evitare di materializzare la chiusura transitiva di un grafo denso e orientato.
Con entrambi gli approcci, ho scoperto che la maggiore complessità nella modifica/assegnazione dei ruoli è compensata dalla facilità/flessibilità risultante nell'assegnazione autorizzazioni a singole parti di dati e che quanto segue per funzionare al meglio:
- Gli utenti possono avere più ruoli
- Ruoli e permessi uniti nella stessa tabella con un flag per distinguere i due (utile durante la modifica di ruoli/permessi)
- I ruoli possono assegnare altri ruoli e ruoli e autorizzazioni possono assegnare autorizzazioni (ma le autorizzazioni non possono assegnare ruoli) dall'interno della stessa tabella.
Il grafico orientato risultante può quindi essere estratto in due query, creato una volta per tutte in un ragionevole lasso di tempo utilizzando la lingua in uso e memorizzato nella cache in Memcache o simili per un uso successivo.
Da lì, estrarre le autorizzazioni di un utente è una questione di verificare quali ruoli ha ed elaborarli utilizzando il grafico delle autorizzazioni per ottenere le autorizzazioni finali. Verificare le autorizzazioni verificando che un utente disponga del ruolo/autorizzazione specificati o meno. E quindi esegui la tua query/emetti un errore in base a quel controllo di autorizzazione.
Puoi estendere il controllo per singoli nodi (ad esempio check_perms($user, 'users.edit', $node)
for "può modificare questo nodo" vs check_perms($user, 'users.edit')
per "può modificare un nodo"), se necessario, e avrai qualcosa di molto flessibile/facile da usare per gli utenti finali.
Come dovrebbe illustrare l'esempio di apertura, fai attenzione a non orientarti troppo verso le autorizzazioni a livello di riga. Il collo di bottiglia delle prestazioni è meno nel controllare le autorizzazioni di un singolo nodo che nel tirare un elenco di nodi validi (cioè solo quelli che l'utente può visualizzare o modificare). Se non sei (molto) esperto nell'ottimizzazione delle query, ti sconsiglio qualsiasi cosa oltre a flag e user_id campi all'interno delle righe stesse.