التخطي إلى المحتوى الرئيسي

Syntax for Models

  • يجب أن تحتوي تهيئة النموذج (CONF) على أربعة أقسام على الأقل: [request_definition], [policy_definition], [policy_effect], و [matchers].

  • إذا كان النموذج يستخدم التحكم بالوصول بناءً على الدور (RBAC)، فيجب أن يتضمن أيضًا قسم [role_definition].

  • يمكن أن تحتوي تهيئة النموذج (CONF) على تعليقات. تبدأ التعليقات برمز #، وكل ما بعد رمز # سيتم التعليق عليه.

تعريف الطلب

يحدد قسم [request_definition] الوسائط في دالة e.Enforce(...).

[request_definition]
r = sub, obj, act

في هذا المثال، sub, obj, و act تمثل الثلاثي الكلاسيكي للوصول: الكائن الفاعل (الكيان الذي يقوم بالوصول)، الكائن الموصول إليه (المورد المُتاح)، والفعل (طريقة الوصول). ومع ذلك، يمكنك تخصيص تنسيق الطلب الخاص بك. على سبيل المثال، يمكنك استخدام sub, act إذا لم تكن بحاجة إلى تحديد مورد معين، أو sub, sub2, obj, act إذا كان لديك كيانين يقومان بالوصول.

تعريف السياسة

يعتبر [policy_definition] هو التعريف لسياسة. يحدد معنى السياسة. على سبيل المثال، لدينا النموذج التالي:

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

ولدينا السياسة التالية (إذا كانت في ملف سياسة):

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

كل سطر في سياسة يسمى قاعدة سياسة. تبدأ كل قاعدة سياسة بـ نوع السياسة، مثل p أو p2. يستخدم لمطابقة تعريف السياسة إذا كان هناك تعريفات متعددة. تظهر السياسة أعلاه الربط التالي. يمكن استخدام الربط في المطابق.

(alice, data1, read) -> (p.sub, p.obj, p.act)
(bob, write-all-objects) -> (p2.sub, p2.act)
نصيحة

يتم اعتبار العناصر في قاعدة السياسة دائمًا على أنها strings. إذا كان لديك أي أسئلة حول هذا، يرجى الرجوع إلى النقاش في: https://github.com/casbin/casbin/issues/113

تأثير السياسة

[policy_effect] هو التعريف لتأثير السياسة. يحدد ما إذا كان يجب الموافقة على طلب الوصول إذا تطابقت قواعد سياسة متعددة مع الطلب. على سبيل المثال، قاعدة واحدة تسمح والأخرى تمنع.

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

يعني تأثير السياسة أعلاه أنه إذا كان هناك أي قاعدة سياسة مطابقة لـ allow، فإن التأثير النهائي هو allow (المعروف أيضًا بالسماح بالتجاوز). p.eft هو التأثير لسياسة، ويمكن أن يكون إما allow أو deny. هو اختياري، والقيمة الافتراضية هي allow. بما أننا لم نحدده أعلاه، فإنه يستخدم القيمة الافتراضية.

مثال آخر لتأثير السياسة هو:

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

هذا يعني أنه إذا لم يكن هناك قواعد سياسة مطابقة لـ deny، فإن التأثير النهائي هو allow (المعروف أيضًا بالمنع بالتجاوز). some يعني أن هناك قاعدة سياسة مطابقة واحدة. any يعني أن جميع قواعد السياسة المطابقة (غير مستخدم هنا). يمكن حتى ربط تأثير السياسة بالتعبيرات المنطقية:

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

هذا يعني أنه يجب أن يكون هناك على الأقل قاعدة سياسة مطابقة واحدة لـ allow، ولا يمكن أن يكون هناك أي قاعدة سياسة مطابقة لـ deny. لذلك، بهذه الطريقة، يتم دعم كل من التفويضات المسموح بها والممنوعة، والمنع يتجاوز.

ملاحظة

على الرغم من أننا صممنا بناء جملة تأثير السياسة كما هو موضح أعلاه، فإن التنفيذات الحالية تستخدم فقط تأثيرات سياسة محددة مسبقًا. وذلك لأننا وجدنا أنه لا توجد حاجة كبيرة لهذا المستوى من المرونة. لذا الآن، يجب عليك استخدام أحد تأثيرات السياسة المدمجة بدلاً من تخصيص تأثير خاص بك.

تأثيرات السياسة المدمجة المدعومة هي:

تأثير السياسةالمعنىمثال
some(where (p.eft == allow))السماح بالتجاوزACL, RBAC, إلخ.
!some(where (p.eft == deny))المنع بالتجاوزالمنع بالتجاوز
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]
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

أنواع الأقسام المتعددة

إذا كنت بحاجة إلى تعريفات سياسة متعددة أو مطابقين متعددين، يمكنك استخدام p2 أو m2 كأمثلة. في الواقع، يمكن استخدام جميع الأقسام الأربعة المذكورة أعلاه بأنواع متعددة، والصياغة هي r تليها رقم، مثل r2 أو e2. افتراضيًا، يجب أن تتوافق هذه الأقسام الأربعة واحدًا لواحد. على سبيل المثال، سيستخدم قسم r2 الخاص بك فقط المطابق m2 لمطابقة سياسات p2.

يمكنك تمرير EnforceContext كمعامل أول لطريقة enforce لتحديد الأنواع. 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"، وهو العامل الوحيد الذي يحمل اسمًا نصيًا. يتحقق هذا العامل من المصفوفة على الجانب الأيمن لمعرفة ما إذا كانت تحتوي على قيمة مساوية للقيمة على الجانب الأيسر. يتم تحديد المساواة باستخدام عامل ==، ولا يتحقق هذا المكتبة من الأنواع بين القيم. طالما يمكن تحويل قيمتين إلى interface{} ويمكن التحقق من المساواة بينهما باستخدام ==، فسوف يعملان كما هو متوقع. لاحظ أنه يمكنك استخدام معامل للمصفوفة، ولكن يجب أن تكون []interface{}.

يرجى الرجوع أيضًا إلى rbac_model_matcher_using_in_op، keyget2_model، وkeyget_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 أو مقيم التعبير مباشرةً للحصول على نصيحة بشأن تسريع الأداء. لمزيد من التفاصيل، يرجى الرجوع إلى قسم Benchmarks.