Skip to main content

Priority Model

Casbin supports priority-based policy loading.

Load Policy with Implicit Priority

Priority is determined by policy order: policies appearing first have higher priority.

model.conf:

[policy_effect]
e = priority(p.eft) || deny

Load Policy with Explicit Priority

See also: casbin#550

Lower priority values indicate higher priority. Non-numerical priority values are placed last rather than causing errors.

Token name convention

The standard priority token name in policy definitions is "priority". To use a custom token name, call e.SetFieldIndex() after initializing the enforcer and reload policies (see the full example in TestCustomizedFieldIndex).

model.conf:

[policy_definition]
p = customized_priority, sub, obj, act, eft

Golang code example:

e, _ := NewEnforcer("./example/priority_model_explicit_customized.conf",
"./example/priority_policy_explicit_customized.csv")
// Due to the customized priority token, the enforcer fails to handle the priority.
ok, err := e.Enforce("bob", "data2", "read") // the result will be `true, nil`
// Set PriorityIndex and reload
e.SetFieldIndex("p", constant.PriorityIndex, 0)
err := e.LoadPolicy()
if err != nil {
log.Fatalf("LoadPolicy: %v", err)
}
ok, err := e.Enforce("bob", "data2", "read") // the result will be `false, nil`

Explicit priority currently supports only AddPolicy and AddPolicies. Avoid changing the priority attribute when calling UpdatePolicy.

model.conf:

[request_definition]
r = sub, obj, act

[policy_definition]
p = priority, sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = priority(p.eft) || deny

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

policy.csv

p, 10, data1_deny_group, data1, read, deny
p, 10, data1_deny_group, data1, write, deny
p, 10, data2_allow_group, data2, read, allow
p, 10, data2_allow_group, data2, write, allow


p, 1, alice, data1, write, allow
p, 1, alice, data1, read, allow
p, 1, bob, data2, read, deny

g, bob, data2_allow_group
g, alice, data1_deny_group

request:

alice, data1, write --> true // because `p, 1, alice, data1, write, allow` has the highest priority
bob, data2, read --> false
bob, data2, write --> true // because bob has the role of `data2_allow_group` which has the right to write data2, and there's no deny policy with higher priority

Load Policy with Priority Based on Role and User Hierarchy

The role and user inheritance structure must form multiple trees, not graphs. When a user has multiple roles, ensure the user occupies the same hierarchy level in each tree. When two roles share the same level, the policy appearing first takes priority. For details, see casbin#833 and casbin#831.

model.conf:

[request_definition]
r = sub, obj, act

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

[role_definition]
g = _, _

[policy_effect]
e = subjectPriority(p.eft) || deny

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

policy.csv

p, root, data1, read, deny
p, admin, data1, read, deny

p, editor, data1, read, deny
p, subscriber, data1, read, deny

p, jane, data1, read, allow
p, alice, data1, read, allow

g, admin, root

g, editor, admin
g, subscriber, admin

g, jane, editor
g, alice, subscriber

Request:

jane, data1, read --> true // because jane is at the bottom, her priority is higher than that of editor, admin, and root
alice, data1, read --> true

The role hierarchy structure:

role: root
└─ role: admin
├─ role editor
│ └─ user: jane

└─ role: subscriber
└─ user: alice

Automatic priority assignment:

role: root                 # auto priority: 30
└─ role: admin # auto priority: 20
├─ role: editor # auto priority: 10
└─ role: subscriber # auto priority: 10