Skip to main content

RBAC with Domains

Role definition with domains​

In Casbin, roles can be domain-scoped: the same user can have different roles in different domains (tenants). That fits multi-tenant and cloud systems where one user works in many tenants.

Use a role definition with three elements; the third is the domain:

[role_definition]
g = _, _, _

The third field is the domain. Example policy:

p, admin, tenant1, data1, read
p, admin, tenant2, data2, read

g, alice, admin, tenant1
g, alice, user, tenant2

So: admin in tenant1 can read data1. Alice is admin in tenant1 and user in tenant2; she can read data1 but not data2 (only admin in tenant2 can read data2).

Matcher: include the domain in g and require it to match:

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

Custom domain token name​

By convention the domain is named dom, but you can use any name (tenant, workspace, etc.) in the request and policy definitions:

[request_definition]
r = sub, tenant, obj, act

[policy_definition]
p = sub, tenant, obj, act

[role_definition]
g = _, _, _

[matchers]
m = g(r.sub, p.sub, r.tenant) && r.tenant == p.tenant && r.obj == p.obj && r.act == p.act

With pattern matching (e.g. keyMatch) for domains, Casbin infers the domain token from the model as long as the domain is at index 1 in both request and policy:

[matchers]
m = g(r.sub, p.sub, r.tenant) && keyMatch(r.tenant, p.tenant) && r.obj == p.obj && r.act == p.act

For domain APIs (e.g. GetAllUsersByDomain()) with a custom domain token name or position, set the index after creating the enforcer. Full example: rbac_with_domains_model.conf.

Token name and position

The domain is usually named dom and placed second (sub, dom, obj, act). In Go Casbin you can use another name or position; then call e.SetFieldIndex("p", constant.DomainIndex, index) after init so APIs like GetAllUsersByDomain() work correctly.

# Using `domain` instead of `dom`
[policy_definition]
p = sub, obj, act, domain
e.SetFieldIndex("p", constant.DomainIndex, 3) // index starts from 0
users := e.GetAllUsersByDomain("domain1") // without SetFieldIndex, this will raise an error

Nested units​

If the domains form a tree (a company contains divisions and departments) and a role granted at a unit should apply to its whole subtree, see Nested Organizations.

Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.