メインコンテンツにスキップ

Syntax for Models

  • モデル設定(CONF)は、少なくとも4つのセクションを持つべきです:[request_definition][policy_definition][policy_effect]、そして[matchers]

  • モデルがロールベースのアクセス制御(RBAC)を使用する場合、[role_definition]セクションも含めるべきです。

  • モデル設定(CONF)にはコメントを含めることができます。 コメントは#記号で始まり、#記号以降のすべてがコメントアウトされます。

リクエスト定義

[request_definition]セクションは、e.Enforce(...)関数の引数を定義します。

[request_definition]
r = sub, obj, act

この例では、subobjactは、クラシックなアクセストリプルを表しています:主体(アクセスするエンティティ)、オブジェクト(アクセスされるリソース)、アクション(アクセス方法)。 しかし、自分のリクエスト形式をカスタマイズすることもできます。 例えば、特定のリソースを指定する必要がない場合はsub, actを使用するか、2つのアクセスエンティティがある場合はsub, sub2, obj, actを使用することができます。

ポリシー定義

[policy_definition]はポリシーの定義です。 それはポリシーの意味を定義します。 例えば、以下のモデルがあります:

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

そして、以下のポリシーがあります(ポリシーファイル内の場合):

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

ポリシーの各行はポリシールールと呼ばれます。 各ポリシールールはpolicy type、例えばpp2で始まります。 それは複数の定義がある場合にポリシー定義と一致するために使用されます。 上記のポリシーは以下のバインディングを示しています。 バインディングはマッチャーで使用できます。

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

ポリシールールの要素は常にstringsとして扱われます。 これについて質問がある場合は、以下の議論を参照してください:https://github.com/casbin/casbin/issues/113

ポリシー効果

[policy_effect]はポリシー効果の定義です。 それは複数のポリシールールがリクエストに一致する場合、アクセスリクエストが承認されるべきかどうかを決定します。 例えば、一つのルールが許可し、もう一つが拒否します。

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

上記のポリシー効果は、もしallowのポリシールールが一つでも一致するなら、最終的な効果はallow(allow-overrideとも呼ばれる)であることを意味します。 p.eftはポリシーの効果で、allowまたはdenyのいずれかになります。 それはオプションで、デフォルト値はallowです。 上記では指定していないので、デフォルト値を使用します。

ポリシー効果の別の例は次のとおりです:

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

これは、denyの一致するポリシー規則がない場合、最終的な効果はallow(deny-overrideとも呼ばれる)であることを意味します。 someは、一致するポリシー規則が一つ存在することを意味します。 anyは、すべての一致するポリシー規則を意味します(ここでは使用されていません)。 ポリシー効果は論理表現とも結びつけることができます:

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

これは、allowの一致するポリシー規則が少なくとも一つ存在しなければならず、denyの一致するポリシー規則が存在してはならないことを意味します。 したがって、この方法では、許可と拒否の両方の認証がサポートされており、拒否が優先されます。

メモ

ポリシー効果の構文を上記のように設計しましたが、現在の実装ではハードコードされたポリシー効果のみを使用しています。 これは、そのレベルの柔軟性があまり必要ないと判断したためです。 したがって、現時点では、独自のカスタマイズの代わりに組み込みのポリシー効果のいずれかを使用する必要があります。

サポートされている組み込みのポリシー効果は次のとおりです:

ポリシー効果意味
some(where (p.eft == allow))allow-overrideACL、RBACなど
!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)役割に基づく優先度Subject-Priority

Matchers

[matchers]はポリシーマッチャーの定義です。 マッチャーは、ポリシールールがリクエストに対してどのように評価されるかを定義する表現式です。

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

上記のマッチャーは最も単純なもので、リクエストの主体、オブジェクト、アクションがポリシールールのものと一致することを意味します。

マッチャーでは、算術演算子(+, -, *, /)や論理演算子(&&, ||, !)を使用できます。

マッチャー内の表現式の順序

表現式の順序はパフォーマンスに大きな影響を与えます。 詳細については、以下の例をご覧ください:

const rbac_models = `
[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.act
`

func TestManyRoles(t *testing.T) {

m, _ := model.NewModelFromString(rbac_models)
e, _ := NewEnforcer(m, false)

roles := []string{"admin", "manager", "developer", "tester"}

// 2500 projects
for nbPrj := 1; nbPrj < 2500; nbPrj++ {
// 4 objects and 1 role per object (so 4 roles)
for _, role := range roles {
roleDB := fmt.Sprintf("%s_project:%d", role, nbPrj)
objectDB := fmt.Sprintf("/projects/%d", nbPrj)
e.AddPolicy(roleDB, objectDB, "GET")
}
jasmineRole := fmt.Sprintf("%s_project:%d", roles[1], nbPrj)
e.AddGroupingPolicy("jasmine", jasmineRole)
}

e.AddGroupingPolicy("abu", "manager_project:1")
e.AddGroupingPolicy("abu", "manager_project:2499")

// With same number of policies
// User 'abu' has only two roles
// User 'jasmine' has many roles (1 role per policy, here 2500 roles)

request := func(subject, object, action string) {
t0 := time.Now()
resp, _ := e.Enforce(subject, object, action)
tElapse := time.Since(t0)
t.Logf("RESPONSE %-10s %s\t %s : %5v IN: %+v", subject, object, action, resp, tElapse)
if tElapse > time.Millisecond*100 {
t.Errorf("More than 100 milliseconds for %s %s %s : %+v", subject, object, action, tElapse)
}
}

request("abu", "/projects/1", "GET") // really fast because only 2 roles in all policies and at the beginning of the casbin_rule table
request("abu", "/projects/2499", "GET") // fast because only 2 roles in all policies
request("jasmine", "/projects/1", "GET") // really fast at the beginning of the casbin_rule table

request("jasmine", "/projects/2499", "GET") // slow and fails the only 1st time <<<< pb here
request("jasmine", "/projects/2499", "GET") // fast maybe due to internal cache mechanism

// same issue with non-existing roles
// request("jasmine", "/projects/999999", "GET") // slow fails the only 1st time <<<< pb here
// request("jasmine", "/projects/999999", "GET") // fast maybe due to internal cache mechanism
}

強制実行時間は非常に長く、最大6秒になることがあります。

go test -run ^TestManyRoles$ github.com/casbin/casbin/v2 -v

=== RUN TestManyRoles
rbac_api_test.go:598: RESPONSE abu /projects/1 GET : true IN: 438.379µs
rbac_api_test.go:598: RESPONSE abu /projects/2499 GET : true IN: 39.005173ms
rbac_api_test.go:598: RESPONSE jasmine /projects/1 GET : true IN: 1.774319ms
rbac_api_test.go:598: RESPONSE jasmine /projects/2499 GET : true IN: 6.164071648s
rbac_api_test.go:600: More than 100 milliseconds for jasmine /projects/2499 GET : 6.164071648s
rbac_api_test.go:598: RESPONSE jasmine /projects/2499 GET : true IN: 12.164122ms
--- FAIL: TestManyRoles (6.24s)
FAIL
FAIL github.com/casbin/casbin/v2 6.244s
FAIL

しかし、マッチャー内の表現式の順序を調整し、関数のような時間がかかる表現式を後ろに置くと、実行時間は非常に短くなります。

上記の例でマッチャー内の表現式の順序を次のように変更します:

[matchers]
m = r.obj == p.obj && g(r.sub, p.sub) && r.act == p.act
go test -run ^TestManyRoles$ github.com/casbin/casbin/v2 -v
=== RUN TestManyRoles
rbac_api_test.go:599: RESPONSE abu /projects/1 GET : true IN: 786.635µs
rbac_api_test.go:599: RESPONSE abu /projects/2499 GET : true IN: 4.933064ms
rbac_api_test.go:599: RESPONSE jasmine /projects/1 GET : true IN: 2.908534ms
rbac_api_test.go:599: RESPONSE jasmine /projects/2499 GET : true IN: 7.292963ms
rbac_api_test.go:599: RESPONSE jasmine /projects/2499 GET : true IN: 6.168307ms
--- PASS: TestManyRoles (0.05s)
PASS
ok github.com/casbin/casbin/v2 0.053s

複数のセクションタイプ

複数のポリシー定義やマッチャーが必要な場合、p2m2を例に使用できます。 実際、上記の4つのセクションすべては複数のタイプを使用でき、構文はrに続けて数字を付ける、例えばr2e2です。 デフォルトでは、これら4つのセクションは一対一に対応するべきです。 例えば、あなたのr2セクションは、p2ポリシーにマッチするためにm2マッチャーのみを使用します。

EnforceContextenforceメソッドの最初のパラメータとして渡すことで、タイプを指定できます。 EnforceContextは次のように定義されています:

EnforceContext{"r2","p2","e2","m2"}
type EnforceContext struct {
RType string
PType string
EType string
MType string
}

ここに使用例があります。 モデルポリシーを参照してください。 リクエストは次のとおりです:

// Pass in a suffix as a 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

特別な文法

また、テキスト名を持つ唯一の演算子である"in"演算子を使用することもできます。 この演算子は、右側の配列が左側の値と等しい値を含んでいるかどうかをチェックします。 等価性は==演算子を使用して判断され、このライブラリは値間の型をチェックしません。 2つの値がinterface{}にキャストでき、==で等価性をチェックできる限り、期待通りに動作します。 配列にパラメータを使用することもできますが、それは[]interface{}でなければなりません。

rbac_model_matcher_using_in_opkeyget2_modelkeyget_modelも参照してください。

例:

[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"}})

表現式評価器

Casbinのマッチャー評価は、各言語の表現式評価器によって実装されています。 Casbinは、統一されたPERM言語を提供するために、彼らの力を統合します。 ここで提供されるモデル構文に加えて、これらの表現評価器は、他の言語や実装ではサポートされていない可能性のある追加の機能を提供することがあります。 この機能を使用する際には注意してください。

各Casbin実装で使用される表現評価器は次のとおりです:

実装言語表現評価器
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/Common/Third%20Party/TExpressionParser
casbin-rsRusthttps://github.com/jonathandturner/rhai
casbin-cppC++https://github.com/ArashPartow/exprtk
メモ

Casbinでパフォーマンスの問題に遭遇した場合、それはおそらく式評価器の効率の低さが原因です。 パフォーマンスの向上についてのアドバイスを求めるために、問題をCasbinまたは式評価器に直接報告することができます。 詳細については、ベンチマークセクションを参照してください。