Ana içeriğe atla

Syntax for Models

  • Bir model yapılandırması (CONF), en az dört bölüm içermelidir: [request_definition], [policy_definition], [policy_effect], ve [matchers].

  • Eğer bir model Rol Tabanlı Erişim Kontrolü (RBAC) kullanıyorsa, [role_definition] bölümünü de içermelidir.

  • Bir model yapılandırması (CONF) yorumlar içerebilir. Yorumlar # sembolü ile başlar ve # sembolünden sonraki her şey yorum olarak kabul edilir.

İstek tanımı

[request_definition] bölümü, e.Enforce(...) fonksiyonundaki argümanları tanımlar.

[request_definition]
r = sub, obj, act

Bu örnekte, sub, obj, ve act klasik erişim üçlüsünü temsil eder: konu (erişim sağlayan varlık), nesne (erişilen kaynak) ve eylem (erişim yöntemi). Ancak, kendi istek formatınızı özelleştirebilirsiniz. Örneğin, belirli bir kaynağı belirtmenize gerek yoksa sub, act kullanabilirsiniz veya iki erişim varlığınız varsa sub, sub2, obj, act kullanabilirsiniz.

Politika Tanımı

[policy_definition], bir politika için tanımı ifade eder. Politikanın anlamını belirler. Örneğin, aşağıdaki modelimiz var:

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

Ve aşağıdaki politikamız var (eğer bir politika dosyasında ise):

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

Bir politika içindeki her satır bir politika kuralı olarak adlandırılır. Her politika kuralı, p veya p2 gibi bir politika tipi ile başlar. Eğer birden fazla tanım varsa, politika tanımıyla eşleştirmek için kullanılır. Yukarıdaki politikada aşağıdaki bağlama gösterilmektedir. Bağlama eşleştiricide kullanılabilir.

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

Bir politika kuralındaki öğeler her zaman dizeler olarak kabul edilir. Bu konuda herhangi bir sorunuz varsa, lütfen şu tartışmaya başvurun: https://github.com/casbin/casbin/issues/113

Politika Etkisi

[policy_effect], politika etkisi için tanımdır. Birden fazla politika kuralı isteğe uyarlarsa, erişim isteğinin onaylanıp onaylanmayacağını belirler. Örneğin, bir kural izin verir ve diğeri reddeder.

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

Yukarıdaki politika etkisi, eğer izin ver şeklinde eşleşen herhangi bir politika kuralı varsa, son etkinin izin ver olduğu anlamına gelir (ayrıca izin-geçersiz kılma olarak da bilinir). p.eft, bir politika için etkidir ve izin ver ya da reddet olabilir. İsteğe bağlıdır ve varsayılan değer allow şeklindedir. Yukarıda belirtmediğimiz için, varsayılan değeri kullanır.

Politika etkisi için başka bir örnek:

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

Bu, eğer deny şeklinde eşleşen bir politika kuralı yoksa, son etkinin allow (deny-override olarak da bilinir) olduğu anlamına gelir. some demek, eşleşen bir politika kuralının var olduğu anlamına gelir. any demek, tüm eşleşen politikaların (burada kullanılmaz) olduğu anlamına gelir. Politika etkisi, mantıksal ifadelerle bile bağlantılı olabilir:

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

Bu, en az bir tane allow şeklinde eşleşen politika kuralı olması gerektiği ve hiçbir deny şeklinde eşleşen politika kuralı olmaması gerektiği anlamına gelir. Bu şekilde, hem izin verme hem de reddetme yetkilendirmeleri desteklenir ve reddetme geçersiz kılar.

not

Politika etkisinin sözdizimini yukarıdaki gibi tasarlamış olsak da, mevcut uygulamalar sadece sabit kodlanmış politika etkilerini kullanmaktadır. Bunun nedeni, o seviyede esnekliğe pek ihtiyaç olmadığını bulmamızdır. Bu nedenle şimdilik, kendi özel politikanızı özelleştirmek yerine yerleşik bir politika etkisinden birini kullanmalısınız.

Desteklenen yerleşik politika etkileri şunlardır:

Politika EtkisiAnlamıÖrnek
some(where (p.eft == allow))izin-geçersiz kılmaACL, RBAC, vb.
!some(where (p.eft == deny))reddet-geçersiz kılReddet-geçersiz kıl
bazı(nerede (p.eft == izin)) && !bazı(nerede (p.eft == reddet))izin-ve-reddetİzin-ve-reddet
öncelik(p.eft) || reddetöncelikÖncelik
konuÖnceliği(p.eft)rol bazlı öncelikSubject-Priority

Eşleştiriciler

[matchers] politikalar için eşleştiricilerin tanımıdır. Eşleştiriciler, politikaların kurallarının talebe göre nasıl değerlendirileceğini belirleyen ifadelerdir.

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

Yukarıdaki eşleştirici en basitidir ve bir talebin konusu, nesnesi ve eyleminin bir politika kuralındakiyle eşleşmesi gerektiği anlamına gelir.

+, -, *, / gibi aritmetik operatörler ve &&, ||, ! gibi mantıksal operatörler eşleştiricilerde kullanılabilir.

Eşleştiricilerde ifadelerin sırası

İfadelerin sırası performansı büyük ölçüde etkileyebilir. Daha fazla detay için aşağıdaki örneğe göz atın:

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
}

Uygulama süresi çok uzun olabilir, 6 saniyeye kadar.

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

Ancak, eşleştiricilerdeki ifadelerin sırasını ayarlayarak ve fonksiyonlar gibi zaman alıcı ifadeleri arkaya koyarak, yürütme süresi çok kısa olacaktır.

Yukarıdaki örnekte eşleştiricilerdeki ifadelerin sırasını şu şekilde değiştirmek:

[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

Çoklu Bölüm Tipleri

Eğer birden fazla politikayı tanımlamanız veya birden fazla eşleştiriciye ihtiyacınız varsa, p2 veya m2 örneklerini kullanabilirsiniz. Aslında, yukarıda bahsedilen dört bölümün hepsi çoklu tipler kullanabilir ve sözdizimi r ve ardından bir sayıdır, örneğin r2 veya e2. Varsayılan olarak, bu dört bölüm bire bir eşleşmelidir. Örneğin, r2 bölümünüz sadece m2 eşleştiriciyi kullanarak p2 politikalarını eşleştirecektir.

enforce metodunun ilk parametresi olarak bir EnforceContext geçirebilirsiniz. EnforceContext şu şekilde tanımlanmıştır:

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

İşte bir örnek kullanım. Lütfen model ve policy dosyalarına başvurun. İstek şu şekildedir:

// 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

Özel Gramer

Ayrıca "in" operatörünü de kullanabilirsiniz, bu tek metin adına sahip olan operatördür. Bu operatör, sağ taraftaki dizinin, sol taraftaki değere eşit bir değer içerip içermediğini kontrol eder. Eşitlik == operatörü kullanılarak belirlenir ve bu kütüphane değerler arasındaki türleri kontrol etmez. İki değer interface{}'e dönüştürülebilir ve hala == ile eşitlik kontrolü yapılabilirse, beklendiği gibi çalışacaklardır. Dizinin parametre olarak kullanılabileceğini unutmayın, ancak bu bir []interface{} olmalıdır.

Ayrıca rbac_model_matcher_using_in_op, keyget2_model ve keyget_model dosyalarına da başvurun.

Örnek:

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

İfade Değerlendirici

Casbin'de eşleştirici değerlendirme, her dilin ifade değerlendiricileri tarafından uygulanmaktadır. Casbin, güçlerini birleştirerek birleşik PERM dilini sağlar. Burada sağlanan model sözdizimine ek olarak, bu ifade değerlendiriciler başka bir dil veya uygulama tarafından desteklenmeyebilecek ek işlevler sunabilir. Lütfen bu işlevselliği kullanırken dikkatli olun.

Her Casbin uygulaması tarafından kullanılan ifade değerlendiriciler şunlardır:

UygulamaDilİfade Değerlendirici
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
not

Eğer Casbin ile bir performans sorunu yaşıyorsanız, muhtemelen ifade değerlendiricinin düşük verimliliği yüzündendir. Sorunu Casbin'e veya ifade değerlendiriciye doğrudan danışarak performansı hızlandırma konusunda tavsiye alabilirsiniz. Daha fazla ayrıntı için lütfen Kıyaslamalar bölümüne bakın.