Come progettare un sistema di controllo degli accessi basato su un ruolo gerarchico

L'accordo di base è che abbiamo un "kickstart" personalizzato per i nostri progetti. Per questo stiamo cercando di rifare il controllo dell'utente. So che ci sono un sacco di domande sul generale rbac, ma non riesco a trovarne alcuna su rbac gerarchico?

I nostri requisiti sono:

  • I ruoli possono essere assegnati alle autorizzazioni di gruppo
  • Se il ruolo non ha una voce di authorization, viene automaticamente negato
  • A un utente possono essere assegnate autorizzazioni di sovrascrittura
  • Gli utenti che annullano le autorizzazioni possono concedere o negare
  • Se a un utente viene negata esplicitamente un'authorization, indipendentemente da quali siano i ruoli "concessi", l'override vince.
  • Gli utenti possono avere più ruoli
  • I ruoli possono avere gerarchia
  • I ruoli possono ereditare da altri ruoli (ad es. Un ruolo "Forum Super Moderatore" è un "Moderatore del forum" e un "Gestore del sistema", e il ruolo "Moderatore del forum" eredita già dal ruolo "Utente del forum")
  • I ruoli che ereditano da un altro ruolo che negano o concedono un privilegio sovrascrivono il loro permesso figlio
  • Le autorizzazioni sono raggruppate per "module" (ad esempio un module "Blog" può avere un permesso di "modifica" e un module "Forum" può avere un permesso di "modifica" e non si scontreranno)
  • Esiste un permesso "Tutto e niente" che garantisce automaticamente l'accesso completo

Quindi, con quei requisiti fuori mano, ecco come sto pensando di farlo.

Tabella: utenti

id | int | unique id 

Tabella: ruoli

 id | int | unique id --------------|--------------------------------------------- title | varchar | human readable name 

Tabella: autorizzazioni

 id | int | unique id --------------|--------------------------------------------- module | varchar | module name --------------|--------------------------------------------- title | varchar | human readable name --------------|--------------------------------------------- key | varchar | key name used in functions 

Tabella: Role_User

 role_id | int | id from roles table --------------|--------------------------------------------- user_id | int | id from users table 

Tabella: Permission_Role

 id | int | unique id --------------|--------------------------------------------- permission_id | int | id from permissions table --------------|--------------------------------------------- role_id | int | id from roles table --------------|--------------------------------------------- grant | tinyint | 0 = deny, 1 = grant 

Tabella: Permission_User

 id | int | unique id --------------|--------------------------------------------- permission_id | int | id from permissions table --------------|--------------------------------------------- user_id | int | id from users table --------------|--------------------------------------------- grant | tinyint | 0 = deny, 1 = grant 

Beh, in realtà è metà, quella parte di cui sono sicuro, la parte su cui mi sto bloccando sono i ruoli gerarchici.

Quindi, come posso progettare questo? La mia idea è che per salvare le query del database sto solo costruendo la matrix delle autorizzazioni all'accesso e salvandola in session in modo che le query non debbano essere troppo semplici poiché vengono eseguite una sola volta per each accesso.

Il problema che vedo è che avrò bisogno di conoscere la gerarchia dei ruoli in modo da poter risolvere le autorizzazioni dei ruoli ereditati prima di risolvere l'ereditarietà.

Le autorizzazioni utente sono la parte facile, le autorizzazioni per utente sono essenzialmente il gruppo finalmente risolto.

Esiste un modo per implementare l'ereditarietà del ruolo utilizzando la relazione ricorsiva sui Roles tabella, facendo riferimento al ruolo a un altro record:

1: n ereditarietà

Questa relazione aggiungerà 1 : n ereditarietà nel record dei Roles . È ansible get un integer tree gerarchico con questa function memorizzata:

 CREATE FUNCTION `getHierarchy`(`aRole` BIGINT UNSIGNED) RETURNS VARCHAR(1024) NOT DETERMINISTIC READS SQL DATA BEGIN DECLARE `aResult` VARCHAR(1024) DEFAULT NULL; DECLARE `aParent` BIGINT UNSIGNED; SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aRole`); WHILE NOT `aParent` IS NULL DO SET `aResult` = CONCAT_WS(',', `aResult`, `aParent`); SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aParent`); END WHILE; RETURN IFNULL(`aResult`, ''); END 

Quindi, potresti get tutte le autorizzazioni concesse con qualcosa del genere:

 SELECT `permission_id` FROM `Permission_Role` WHERE FIND_IN_SET(`role_id`, `getHierarchy`({$role})) AND grant; 

Se non è sufficiente, potresti fare un'altra tabella per ereditarietà:

n: m ereditarietà

Ma, in questo caso, era necessario un altro algorithm di ottenimento della gerarchia.


Per risolvere il problema di sovrascrittura devi get permessi di ruolo e permessi utente. Quindi, scrivere user autorizzazioni user sui permessi dei roles per la session .


Inoltre, suggerisco di rimuovere le colonne di grant in Permission_Role e Permission_User . Non è necessario mappare each authorization per ognuno di essi. Quanto basta per usare le query EXISTS : se c'è un record, allora il permesso è concesso, altrimenti – non lo è. Se è necessario recuperare tutte le autorizzazioni e gli stati, è ansible utilizzare LEFT JOIN s.