role-based access control (RBAC) for multi domain/tenant implementation in Golang (casbin wrapper)
gate is go package for RBAC with multi tenant/domain, this one is implement base on casbin, some feature that useful for multi domain was added.
//permission is contain module name and action name
//policy type p -> role writer in domain1 has write permission in module data1
p, writer, domain1, data1, write
//policy type p -> role visitor3 in domain3 has all permission in module data3
p, visitor3, domain3, data3, *
//policy type g -> alice is admin role in domain1 (notice : admin role has all permission in this domain)
g, alice, admin, domain1
//policy type g -> alice is visitor3 role in domain3
g, alice, visitor3, domain3
if you need more information please follow the casbin document casbin document
go get -u github.com/panapol-p/gate
you can use another adapter to store casbin policy (mongo,postgresql,mysql,aws s3 or etc.) by follow casbin adapter casbin adapter
notice : some adapter is not support auto-save
when you update policy or rule you must save and load policy by using g.Load()
or g.Save()
notice2 : if you need to use some feature from native casbin you can called by using g.E
this one is natice casbin enforcer
notice3 : if you build aplication that support scalable mode , please don't forget to set casbin watcher to trigger event when some node has policy update, another node will know and use g.Load()
for update policy each node otherwise all of your node will be not use same policy rules
func main(){
//set adapter
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
//create new gate
g, err := NewGate(a)
}
ex. usecase -> manage user role and permission in user management notice : you can use userID (like "1234-1234-234-345") instead of user name (like "bella"), roleID too , we try to explain by using name for easy to understand and dont forget user and role must be unique in that domain if not it will be overwrite or add more policy
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
// assign permission:write for module:resource1 to role:dep1 in domain:domain5
err = g.AssignPermissionToRole("domain5", "dep1", "resource1", "write")
// assign role:dep1 to user:bella in domain:domain5
err = g.AssignRoleToUser("domain5", "dep1", "bella")
}
ex. usecase -> manage user role and permission in user management
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
// revoke permission:write for module:resource1 to role:dep1 in domain:domain5
err = g.RevokerPermissionToRole("domain5", "dep1", "resource1", "write")
// revoke role:dep1 to user:bella in domain:domain5
err = g.RevokeRoleToUser("domain5", "dep1", "bella")
}
ex. usecase -> middleware for http request
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//user:bella has permission:write for module:resource1 in domain:domain5 or not?
h, err = g.HasPermission("domain5", "bella", "resource1", "write")
//output : true / false
}
ex. usecase -> middleware for admin http request
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//user:alice is role:admin in domain:domain1 or not?
isAdmin := g.IsAdmin("domain1", "alice")
//output : true / false
}
ex. usecase -> show all role in user management page
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//list all role in domain:domain1
r1 := g.GetRoles("domain1")
//output : domain1 has role:admin , writer , reader , visitor
//output : []string{"admin", "writer", "reader", "visitor"}
}
ex. usecase -> show all user with role in user management page
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//list all user with role in domain:domain1
u := g.GetAllUsersRole("domain1")
//output : domain1 has user:alice with role:admin and user:bob with role:reader
//output []UserRole{ {"alice", "admin"}, {"bob", "reader"}}
}
ex. usecase -> manage permission in role in user management page
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//list all permission for role:writer in domain:domain1
//notice : if you use admin it will be return all permission in this domain
p := g.GetPermissionsForRole("domain1", "writer")
//output : combine module and permission(action) with dot
//output : role:wrtiter in domain1 has read and write in module:data1
//output : []string{"data1.read", "data1.write"}
}
ex. usecase -> get role by user
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//list all role by user user:alice in domain:domain1
r := g.GetUserRole("domain2", "alice")
//output : []string{"admin"}
}
ex. usecase -> some application need to count the number of module usage
func main(){
a := fileadapter.NewAdapter("./testdata/rbac_with_domains_policy.csv")
g, err := NewGate(a)
//list all module with number of usage in domain:domain1
m := g.CountModule("domain1")
//output : domain1 use module:data2 1 license and use module:data3 2 licenses
//output : map[string]int{ "data2": 1, "data3": 2}
}
ex. usecase -> some application need to limit the number of module usage
Distributed under the MIT License. See license for more information.
Contributions are welcome! Feel free to check our open issues.