Gestione permessi con bitwise

Normalmente la gestione RBAC di utenti, ruoli e permessi nelle applicazioni web viene sviluppata realizzando (appunto) una tabella per gli utenti, una per i ruoli e una per i permessi alle quali vanno aggiunte due tabelle pivot per gestire le relazioni tra utenti e ruoli e tra ruoli e permessi. Ma, se il tipo di progetto non e’ troppo complesso, esistono soluzioni molto piu’ semplici e veloci da realizzare e da mantenere.

Se avete voglia di sperimentare qualcosa di nuovo e le vostre necessita’ per quanto riguarda la gestione dei permessi non sono troppo articolate esiste una soluzione molto semplice che consente di gestire i permessi dei nostri utenti utilizzando solo due tabelle. Il tutto grazie all’ operatore bitwise AND che effettua comparazioni tra operandi a livello di bit e non di valore numerico. Vediamo un esempio pratico.

Prima di tutto creiamo lo schema del database:

Lo schema e’ volutamente ridotto al minimo indispensabile per la nostra piccola dimostrazione e contiene gia’ i dati che ci serviranno per vedere come realizzare le query necessarie a gestire il sistema RBAC.

Il valore del campo “bit” della tabella “permissions” dovra’ essere inserito raddoppiando il valore del bit piu’ alto presente nella tabella. Quindi il primo valore di “bit” sara’ 1 e poi di conseguenza 2, 4, 8, 16, 32, 64, 128 ecc…

Come vedete, nei dati del campo “permissions” della tabella “users”, e’ presente un valore numerico. Questo valore e’ la somma aritmetica dei valori del campo “bit” della tabella “permissions” dei permessi che vogliamo assegnare all’ utente. Se non mi sono spiegato bene, andate avanti ugualmente, sara’ tutto chiaro tra poco.

L’ operatore bitwise “&” nelle query SQL effettua un AND sui singoli bit degli operatori e non sul loro valore numerico. Questo ci consente di avere a disposizione le query necessarie per recuperare i permessi di un determinato utente e per stabilire chi ha uno specifico permesso.

Recuperare i permessi di un utente

Recuperare quali utenti hanno un determinato permesso

Ad esempio, l’ utente Gino nella nostra tabella “users” ha un valore “permission” di 7, che equivale alla somma dei valori di “bit” della tabella “permissions” per i permessi di “create”, “read” e “update” (1 + 2 + 4). Ed ecco che abbiamo tutto il necessario per implementare il nostro sistema RBAC.

Il piu’ grosso inconveniente di questo sistema e’ che i permessi creabili non sono infiniti e quindi, gia’ se dobbiamo gestire piu’ di venti o trenta permessi diversi, ci conviene usare un approccio diverso. Il limite teorico e’ molto superiore su qualunque tipo di macchina recente, ma il valore “bit” del trentesimo permesso sara’ gia’ 536.870.912, quindi determinare quale intero raggruppa determinati permessi diventa ingestibile.

In realta’ esiste una implementazione che sfrutta questo meccanismo e che ritengo sia particolarmente adatta per la gestione di applicazioni web. E’ sufficiente sostituire alla tabella dei permessi “permissions” la tabella dei ruoli “roles” e inserire all’ interno di quest’ ultima tabella un campo “permissions”, che conterra’, per ogni record di “roles”, un json con l’ elenco dei permessi accordati a quel ruolo.

Ecco che possiamo gestire in maniera semplice una trentina di ruoli ognuno dei quali puo’ avere virtualmente infiniti permessi.

Un ulteriore miglioramento, che rende questo approccio molto adatto allo sviluppo di applicazioni web, e’ di inserire all’ interno del json dei permessi delle espressioni regolari con le quali effettuare automaticamente il match con le uri della nostra applicazione.

Ecco che, se progettiamo bene le routes dell’ applicazione, avremo di conseguenza gia’ pronto anche il grosso della gestione dei permessi. Bastera’ verificare il match tra la uri richiamata da un utente e le uri che gli sono consentite. Ad esempio, la uri “/admin/users/5/update” sara’ accessibile a chi avra’ il permesso “admin/users/\d+/(udpate|delete)“.

Ovviamente sara’ necessario generare apposite uri per i casi particolari. Per fare un esempio di un caso reale e probabile, se un utente dovra’ poter modificare solo i propri dati, andra’ creata la uri “/user/update” che consente di effettuare modifiche solo all’ utente loggato su se stesso.

Come vedete e’ un argomento molto corposo, ma molto interessante e spero di trovare presto il tempo per scrivere i dettagli di questa implementazione.