Casbin
Repository ufficiale: casbin/casbin: An authorization library that supports access control models like ACL, RBAC, ABAC in Golang (github.com)
Documentazione ufficiale: Panoramica | Casbin
TIP
Questo articolo può essere considerato come un articolo introduttivo su Casbin. Se desideri approfondire ulteriormente, visita il sito ufficiale.
Introduzione
In un sistema, i programmatori backend devono essere responsabili della gestione delle autorizzazioni per le API, il che richiede molto lavoro. Se ogni progetto deve scrivere manualmente un proprio sistema, sarà uno spreco enorme di tempo. Le grandi aziende con più risorse umane e materiali tendono a sviluppare autonomamente un framework di autorizzazione, ma la maggior parte delle piccole e medie imprese non può sostenere questi costi di sviluppo. Pertanto, i framework di autorizzazione open source sul mercato diventano la loro scelta preferita. Casbin è proprio una libreria di controllo accessi open source ed efficiente, sviluppata in Go, ma supporta anche altri linguaggi principali.
Va notato che Casbin è solo un framework di controllo accessi, responsabile solo del controllo degli accessi. La logica di autenticazione degli accessi non è di competenza di Casbin, che memorizza solo le relazioni di mappatura tra utenti e ruoli. Supporta i seguenti modelli di controllo accessi:
- ACL (Access Control List, Lista di Controllo Accessi)
- ACL con superutente
- ACL senza utenti: particolarmente utile per sistemi senza autenticazione o login utente.
- ACL senza risorse: alcuni scenari possono riguardare solo i tipi di risorse, non le singole risorse, come i permessi
write-article,read-log. Non controlla l'accesso a articoli o log specifici. - RBAC (Controllo Accessi Basato sui Ruoli)
- RBAC con ruoli risorsa: gli utenti e le risorse possono avere contemporaneamente ruoli (o gruppi).
- RBAC con domini/tenant: gli utenti possono impostare diversi insiemi di ruoli per diversi domini/tenant.
- ABAC (Controllo Accessi Basato sugli Attributi): supporta l'uso di sintassi come
resource.Ownerper ottenere attributi di elementi. - RESTful: supporta percorsi come
/res/*,/res/: ide metodi HTTP comeGET,POST,PUT,DELETE. - Priorità al rifiuto: supporta autorizzazioni consentite e rifiutate, il rifiuto ha priorità sul consenso.
- Priorità: le regole delle policy sono prioritarie in base al loro ordine, simile alle regole del firewall.
Come Funziona
In Casbin, i modelli di controllo accessi sono astratti in file di configurazione basati su PERM, dove PERM sta per Policy (politica), Effect (effetto), Request (richiesta), Matcher (corrispondenza). Quando si modifica il meccanismo di autorizzazione nel progetto, è sufficiente modificare semplicemente il file di configurazione. Il contenuto di un file Model normale è il seguente:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actQuesto è il modello di controllo accessi ACL più semplice.
Policy
Nel file di configurazione, la parte di definizione della policy è
[policy_definition]
p = sub, obj, actp indica policy e non può essere sostituito da altri caratteri. sub indica subject (soggetto), obj indica object (oggetto), act indica action (azione).
p = sub, obj, actPuò esserci anche un quarto campo eft, che se omesso è impostato su allow per impostazione predefinita.
p=sub, obj, act, eftQuesta riga descrive solo come scrivere la policy, non è la definizione concreta della policy. Di seguito è riportato un esempio concreto di policy:
p, jojo, cake, eatp rappresenta che questa è una definizione di regola di policy, jojo è il soggetto della policy, cake è l'oggetto della policy, eat è l'azione. Il significato completo è che il soggetto jojo può eseguire l'azione eat sull'oggetto cake. Le regole concrete della policy non appariranno nel file del modello; ci saranno file di policy dedicati o database per memorizzare le policy.
Richiesta
Nel file di configurazione, la parte di definizione della richiesta è
[request_definition]
r = sub, obj, actr indica request e non può essere sostituito da altri caratteri. sub indica il soggetto della richiesta, obj indica l'oggetto della richiesta, act indica l'azione della richiesta. Generalmente la definizione della richiesta e la definizione della policy hanno gli stessi nomi di campo. La parte della richiesta non è gestita da Casbin; spetta allo sviluppatore decidere cosa è il soggetto della richiesta e cosa è l'oggetto della richiesta. Casbin deve solo eseguire il controllo degli accessi in base ai campi passati.
Corrispondenza
Nel file di configurazione, la parte di definizione della corrispondenza è
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actm indica matcher e non può essere sostituito da altri caratteri. Dopo di esso ci sono le regole di corrispondenza corrispondenti. Quanto sopra è una semplice espressione booleana che significa che tutti i campi della richiesta passati corrispondono a tutti i campi della regola della policy. Naturalmente, può anche essere un wildcard o un'espressione regolare più potente.
Oltre a ciò, il matcher supporta anche la sintassi in, ad esempio
[matchers]
m = r.sub in ("root","admin")Può anche essere
[matchers]
m = r.sub.Name in (r.obj.Admins)e.Enforce(Sub{Name: "alice"}, Obj{Name: "a book", Admins: []interface{}{"alice", "bob"}})Durante la corrispondenza, Casbin non esegue il controllo dei tipi, ma lo tratta come interface ed esegue un controllo == per verificare l'uguaglianza.
Effetto
La definizione dell'effetto effettua nuovamente una valutazione logica combinata sui risultati della corrispondenza. Nel file di configurazione, la parte di definizione dell'effetto è
[policy_effect]
e = some(where (p.eft == allow))e indica effect e non può essere sostituito da altri caratteri. Il quantificatore some verifica se esiste una regola di policy che soddisfa il matcher. Il quantificatore any verifica se tutte le regole della policy soddisfano il matcher.
some(where (p.eft == allow))Questa regola significa che se nei risultati della corrispondenza c'è un risultato allow, il risultato finale è allow.
e = !some(where (p.eft == deny))Questa regola significa che se nei risultati della corrispondenza non ci sono risultati deny, il risultato finale è allow.
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))Questa regola significa che nei risultati della corrispondenza, se c'è un risultato allow e non ci sono risultati deny, il risultato finale è allow.
Sebbene Casbin abbia progettato la grammatica per questi effetti delle policy, l'esecuzione attuale utilizza solo effetti di policy hardcoded. Ritengono che questa flessibilità non sia particolarmente necessaria. Finora devi utilizzare gli effetti delle policy incorporati e non puoi personalizzarli. Gli effetti delle policy incorporati supportati sono i seguenti.
| Definizione Policy effect | Significato | Esempio |
|---|---|---|
| some(where (p.eft == allow)) | allow-override | ACL, RBAC, ecc. |
| !some(where (p.eft == deny)) | deny-override | Rifiuto sovrascrittura |
| some(where (p.eft == allow)) && !some(where (p.eft == deny)) | allow-and-deny | Consenso e rifiuto |
| priority(p.eft) || deny | priority | Priorità |
| subjectPriority(p.eft) | Priorità basata sui ruoli | Priorità soggetto |
TIP
Le quattro definizioni sopra possono essere definite più volte, la sintassi è
type+number, ad esempior2,p2,e2,m2.I file del modello possono avere commenti, commentati con il simbolo
#.
Esempio
Di seguito è riportato un esempio che dimostra il processo di lavoro del file del modello. Innanzitutto definisci un semplice file di modello ACL come segue
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actIl file Policy è il seguente
p, alice, data1, read
p, bob, data2, writeIl processo di astrazione di soggetto, oggetto e azione è determinato dalla logica di business, che non è importante qui quindi viene omesso. Di seguito viene mostrato il modo più semplice per trasmettere la richiesta:
alice, data1, read
bob, data1, read
alice, data2, write
bob, data2, writeNel file policy è definito che alice ha il permesso di eseguire operazioni di lettura su data1, bob ha il permesso di eseguire operazioni di scrittura su data2. Quindi nelle richieste trasmesse
alice, data1, readindica che alice vuole eseguire un'operazione di lettura su data1,
bob, data1, readindica che bob vuole eseguire un'operazione di lettura su data1, e così via. Il risultato finale è
true
false
false
trueQuesto è un esempio ACL più semplice. Sul sito ufficiale di Casbin è possibile modificare e testare gli esempi online. Vai a Casbin editor per testare.
RBAC
RBAC (Role-Based-Access-Controll), Controllo Accessi Basato sui Ruoli, rispetto al modello ACL avrà un [role definition] in più. Di seguito è riportato un semplice modello RBAC:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.actLa definizione dei ruoli è la seguente
[role_definition]
g = _, _g indica group e non può essere sostituito da altri caratteri. Supporta la creazione di più definizioni con il metodo type+number. _ è un segnaposto che indica quanti parametri di input ci sono. Generalmente, nella Policy, g è solitamente nel seguente formato:
g, alice, data2_admin
g, mike, data1_admin
g, data1_admin data2_adminalice indica il soggetto, data2_admin indica il ruolo. Strettamente parlando, Casbin li tratta come stringhe; come interpretarne il significato e l'uso dipende dallo sviluppatore.
g, alice, data2_adminindica che alice ha il ruolo data2_admin
g, mike, data1_adminindica che mike ha il ruolo data1_admin
g, data1_admin data2_adminindica che il ruolo data1_admin ha il ruolo data2_admin, questa è la relazione di ereditarietà tra i ruoli.
Modello Ruoli Risorsa
Il modello ruoli risorsa aggiunge un g2 come definizione del ruolo della risorsa. La definizione del modello è la seguente
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.actLa definizione di esempio della Policy è la seguente
p, alice, data1, read
p, bob, data2, write
p, data_group_admin, data_group, write
g, alice, data_group_admin
g2, data1, data_group
g2, data2, data_groupg2 definisce il gruppo di ruoli risorsa, assegna le risorse a diversi ruoli e definisce le relazioni utente tra i ruoli utente e i ruoli risorsa.
p, data_group_admin, data_group, writeQuesta regola di policy definisce che un utente con il ruolo data_group_admin può eseguire operazioni di scrittura sulle risorse con il ruolo data_group.
Modello Multi-Tenant/Dominio
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.actIl modello multi-tenant/dominio ha il campo dom in più rispetto al modello RBAC tradizionale, utilizzato per indicare il dominio a cui appartiene il soggetto. La Policy di esempio è la seguente
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write
g, alice, admin, domain1
g, bob, admin, domain2Ad esempio
p, admin, domain1, data1, readdefinisce che il soggetto admin appartenente al dominio domain1 ha il permesso di eseguire operazioni di lettura su data1
g, alice, admin, domain1definisce che alice appartiene a domain1 e ha il ruolo admin
