当前位置: 首页 > 文档资料 > Casbin 中文文档 >

Model语法

优质
小牛编辑
126浏览
2023-12-01
  • Model CONF 至少应包含四个部分: [request_definition], [policy_definition], [policy_effect], [matchers]

  • 如果 model 使用 RBAC, 还需要添加[role_definition]部分。

  • Model CONF 文件可以包含注释。注释以 # 开头, # 会注释该行剩余部分。

Request定义

[request_definition] 部分用于request的定义,它明确了 e.Enforce(...) 函数中参数的含义。

[request_definition]
r = sub, obj, act

sub, obj, act 表示经典三元组: 访问实体 (Subject),访问资源 (Object) 和访问方法 (Action)。 但是, 你可以自定义你自己的请求表单, 如果不需要指定特定资源,则可以这样定义 sub、act ,或者如果有两个访问实体, 则为 sub、sub2、obj、act

Policy定义

[policy_definition] 部分是对policy的定义,以下文的 model 配置为例:

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

这些是我们对policy规则的具体描述

p, alice, data1, read
p2, bob, write-all-objects

policy部分的每一行称之为一个策略规则, 每条策略规则通常以形如p, p2policy type开头。 如果存在多个policy定义,那么我们会根据前文提到的policy type与具体的某条定义匹配。 上面的policy的绑定关系将会在matcher中使用, 罗列如下:

(alice, data1, read) -> (p.sub, p.obj, p.act)
(bob, write-all-objects) -> (p2.sub, p2.act)
tip

The elements in a policy rule are always regarded asstring. If you have any question about this, please see the discussion at: https://github.com/casbin/casbin/issues/113

Policy effect定义

[policy_effect] is the definition for the policy effect. It defines whether the access request should be approved if multiple policy rules match the request. For example, one rule permits and the other denies.

[policy_effect]
e = some(where (p.eft == allow))

The above policy effect means if there's any matched policy rule of allow, the final effect is allow (aka allow-override). p.eft is the effect for a policy, it can be allow or deny. It's optional and the default value is allow. So as we didn't specify it above, it uses the default value.

Another example for policy effect is:

[policy_effect]
e = !some(where (p.eft == deny))

It means if there's no matched policy rules ofdeny, the final effect is allow (aka deny-override). some means: if there exists one matched policy rule. any means: all matched policy rules (not used here). The policy effect can even be connected with logic expressions:

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

It means at least one matched policy rule ofallow, and there is no matched policy rule ofdeny. So in this way, both the allow and deny authorizations are supported, and the deny overrides.

note

Although we designed the syntax of policy effect as above, the current implementations only use hard-coded policy effect, as we found there's no much need for that sort of flexibility. So for now, you must use one of the built-in policy effects instead of customizing your own one.

The supported built-in policy effects are:

Policy effect意义示例
some(where (p.eft == allow))allow-overrideACL, RBAC, etc.
!some(where (p.eft == deny))deny-overrideDeny-override
some(where (p.eft == allow)) && !some(where (p.eft == deny))allow-and-denyAllow-and-deny
priority(p.eft) || denypriorityPriority
subjectPriority(p.eft)基于角色的优先级主题优先级

匹配器

[matchers] is the definition for policy matchers. The matchers are expressions. It defines how the policy rules are evaluated against the request.

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

The above matcher is the simplest, it means that the subject, object and action in a request should match the ones in a policy rule.

You can use arithmetic like +, -, *, / and logical operators like &&, ||, ! in matchers.

Multiple sections type

If you need multiple policy definitions or multiple matcher, you can use like p2, m2. In fact, all of the above four sections can use multiple types and the syntax is r+number, such as r2, e2. By default these four sections should correspond one to one. Such as your r2 will only use matcher m2 to match policies p2.

You can pass in EnforceContext as the first parameter of enforce method to specify the types, the EnforceContext is like this

goNode.js
EnforceContext{"r2","p2","e2","m2"}
type EnforceContext struct {
    RType string
    PType string
    EType string
    MType string
}
const enforceContext = new EnforceContext('r2', 'p2', 'e2', 'm2');
class EnforceContext {
  constructor(rType, pType, eType, mType) {
    this.pType = pType;
    this.eType = eType;
    this.mType = mType;
    this.rType = rType;
  }
}

Example usage, see model and policy, the request is as follows

goNode.js
// Pass in a suffix as parameter to NewEnforceContext,such as 2 or 3 and it will create r2,p2,etc..
enforceContext := NewEnforceContext("2")
// You can also specify a certain type individually
enforceContext.EType = "e"
// Don't pass in EnforceContext,the default is r,p,e,m
e.Enforce("alice", "data2", "read")     // true
// pass in EnforceContext
e.Enforce(enforceContext, struct{ Age int }{Age: 70}, "/data1", "read")     //false
e.Enforce(enforceContext, struct{ Age int }{Age: 30}, "/data1", "read")     //true
// Pass in a suffix as parameter to NewEnforceContext,such as 2 or 3 and it will create r2,p2,etc..
const enforceContext = new NewEnforceContext('2');
// You can also specify a certain type individually
enforceContext.eType = "e"
// Don't pass in EnforceContext,the default is r,p,e,m
e.Enforce("alice", "data2", "read")     // true
// pass in EnforceContext
e.Enforce(enforceContext, {Age: 70}, "/data1", "read")      //false
e.Enforce(enforceContext, {Age: 30}, "/data1", "read")      //true

Special Grammer

You could also use in, the only operator with a text name. This operator checks the right-hand side array to see if it contains a value that is equal to the left-side value. Equality is determined by the use of the == operator, and this library doesn't check types between the values. Any two values, when cast to interface{}, and can still be checked for equality with == will act as expected. Note that you can use a parameter for the array, but it must be an []interface{}.

Also refer to rbac_model_matcher_using_in_op, keyget2_model and keyget_model

Example:

[request_definition]
r = sub, obj
...
[matchers]
m = r.sub.Name in (r.obj.Admins)
e.Enforce(Sub{Name: "alice"}, Obj{Name: "a book", Admins: []interface{}{"alice", "bob"}})

Expression evaluator

The matcher evaluation in Casbin is implemented by expression evaluators in each language. Casbin integrates their powers to provide the unified PERM language. Besides all the model syntax provided here, those expression evaluators may provide extra functionality, which may be not supported by another language or implementation. Use it at your own risk.

The expression evaluators used by each Casbin implementation are:

实现语言表达式运算器
CasbinGolanghttps://github.com/Knetic/govaluate
jCasbinJavahttps://github.com/killme2008/aviator
Node-CasbinNode.jshttps://github.com/donmccurdy/expression-eval
PHP-CasbinPHPhttps://github.com/symfony/expression-language
PyCasbinPythonhttps://github.com/danthedeckie/simpleeval
Casbin.NETC#https://github.com/davideicardi/DynamicExpresso
Casbin4DDelphihttps://github.com/casbin4d/Casbin4D/tree/master/SourceCode/Conce/Third%20Party/TExpressionParser
casbin-rsRusthttps://github.com/jonathandturner/rhai
note

If you encounter performance issue about Casbin, it's probably caused by the low efficiency of the expression evaluator. You can both send issue to Casbin or the expression evaluator directly for advice to speed up. See Benchmarks section for details.

← 支持的Models效果器 →