Langkau ke kandungan utama

Syntax for Models

  • Konfigurasi model (CONF) harus mempunyai sekurang-kurangnya empat bahagian: [request_definition], [policy_definition], [policy_effect], dan [matchers].

  • Jika model menggunakan Kontrol Akses Berbasis Peranan (RBAC), ia juga harus memasukkan bahagian [role_definition].

  • Konfigurasi model (CONF) boleh mengandungi komen. Komen bermula dengan simbol #, dan semua yang berada selepas simbol # akan dikomen keluar.

Definisi permintaan

Bahagian [request_definition] mentakrifkan argumen dalam fungsi e.Enforce(...).

[request_definition]
r = sub, obj, act

Dalam contoh ini, sub, obj, dan act mewakili tiga klasik akses: subjek (entiti yang mengakses), objek (sumber yang diakses), dan tindakan (cara akses). Walau bagaimanapun, anda boleh menyesuaikan format permintaan anda sendiri. Sebagai contoh, anda boleh menggunakan sub, act jika anda tidak perlu menentukan sumber tertentu, atau sub, sub2, obj, act jika anda mempunyai dua entiti yang mengakses.

Takrifan Polisi

[policy_definition] adalah takrifan untuk satu polisi. Ia mentakrifkan makna polisi tersebut. Sebagai contoh, kami mempunyai model berikut:

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

Dan kami mempunyai polisi berikut (jika dalam fail polisi):

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

Setiap baris dalam polisi dipanggil peraturan polisi. Setiap peraturan polisi bermula dengan jenis polisi, seperti p atau p2. Ia digunakan untuk memadankan takrifan polisi jika terdapat beberapa takrifan. Dasar di atas menunjukkan ikatan berikut. Ikatan ini boleh digunakan dalam penapis.

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

Elemen dalam peraturan dasar sentiasa dianggap sebagai rentetan. Sekiranya anda mempunyai sebarang pertanyaan mengenai ini, sila rujuk perbincangan di: https://github.com/casbin/casbin/issues/113

Kesan Dasar

[policy_effect] adalah definisi untuk kesan dasar. Ia menentukan sama ada permintaan akses harus diluluskan jika berbilang peraturan dasar sepadan dengan permintaan tersebut. Contohnya, satu peraturan membenarkan dan yang lain menafikan.

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

Kesan dasar di atas bermakna jika terdapat sebarang peraturan dasar yang sepadan dengan benarkan, kesan akhir adalah benarkan (juga dikenali sebagai benarkan-timpa). p.eft adalah kesan untuk satu dasar, dan ia boleh menjadi sama ada benarkan atau nafi. Ia adalah pilihan, dan nilai lalai ialah allow. Oleh kerana kita tidak menentukannya di atas, ia menggunakan nilai lalai.

Satu lagi contoh untuk kesan dasar ialah:

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

Ini bermakna jika tiada peraturan dasar yang sepadan dengan deny, kesan akhir ialah allow (juga dikenali sebagai deny-override). some bermakna terdapat sekurang-kurangnya satu peraturan dasar yang sepadan. any bermakna semua peraturan dasar yang sepadan (tidak digunakan di sini). Kesan dasar juga boleh dihubungkaitkan dengan ungkapan logik:

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

Ini bermakna mesti ada sekurang-kurangnya satu peraturan dasar yang sepadan dengan allow, dan tidak boleh ada peraturan dasar yang sepadan dengan deny. Oleh itu, dengan cara ini, kedua-dua kebenaran dan penafian diluluskan disokong, dan penafian mengatasi.

nota

Walaupun kita mereka bentuk sintaks kesan dasar seperti di atas, pelaksanaan semasa hanya menggunakan kesan dasar yang dikodkan secara keras. Ini kerana kami mendapati bahawa tidak ada keperluan yang besar untuk tahap fleksibiliti tersebut. Jadi buat masa ini, anda mesti menggunakan salah satu kesan polisi terbina dalam daripada menyesuaikan sendiri.

Kesan polisi terbina dalam yang disokong adalah:

Kesan PolisiMaksudContoh
some(where (p.eft == allow))allow-overrideACL, RBAC, dll.
!some(where (p.eft == deny))tolak-mengatasiTolak-mengatasi
beberapa(tempat (p.eft == benarkan)) && !beberapa(tempat (p.eft == tolak))benarkan-dan-tolakBenarkan-dan-tolak
keutamaan(p.eft) || tolakkeutamaanKeutamaan
keutamaanSubjek(p.eft)keutamaan berdasarkan perananSubjek-Keutamaan

Pemadanan

[pemadanan] adalah definisi untuk pemadanan polisi. Pemadanan adalah ungkapan yang mentakrifkan bagaimana peraturan polisi dinilai terhadap permintaan.

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

Pemadanan di atas adalah yang paling mudah dan bermaksud bahawa subjek, objek, dan tindakan dalam permintaan harus sepadan dengan yang ada dalam peraturan polisi.

Operator aritmetik seperti +, -, *, / dan operator logik seperti &&, ||, ! boleh digunakan dalam pemadanan.

Susunan ungkapan dalam pemadanan

Susunan ungkapan boleh memberi kesan yang besar kepada prestasi. Lihat contoh berikut untuk butiran lanjut:

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
}

Masa penguatkuasaan mungkin sangat lama, sehingga 6 saat.

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

Walau bagaimanapun, jika kita menyesuaikan susunan ungkapan dalam penapis dan meletakkan ungkapan yang memakan lebih banyak masa seperti fungsi di belakang, masa pelaksanaan akan menjadi sangat singkat.

Menukar susunan ungkapan dalam penapis dalam contoh di atas kepada:

[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

Pelbagai Jenis Bahagian

Jika anda memerlukan pelbagai definisi polisi atau pelbagai penapis, anda boleh menggunakan p2 atau m2 sebagai contoh. Sebenarnya, keempat-empat bahagian yang dinyatakan di atas boleh menggunakan pelbagai jenis, dan sintaksnya adalah r diikuti dengan nombor, seperti r2 atau e2. Secara lalai, keempat-empat bahagian ini harus sepadan satu-dengan-satu. Sebagai contoh, bahagian r2 anda hanya akan menggunakan penapis m2 untuk memadankan polisi p2.

Anda boleh menyampaikan EnforceContext sebagai parameter pertama kaedah enforce untuk menentukan jenis. EnforceContext ditakrifkan seperti berikut:

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

Berikut adalah contoh penggunaan. Sila rujuk kepada model dan polisi. Permintaannya adalah seperti berikut:

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

Tatabahasa Khas

Anda juga boleh menggunakan operator "in", yang merupakan satu-satunya operator dengan nama teks. Operator ini memeriksa tatasusunan di sebelah kanan untuk melihat sama ada ia mengandungi nilai yang sama dengan nilai di sebelah kiri. Kesamaan ditentukan dengan menggunakan operator ==, dan perpustakaan ini tidak menyemak jenis antara nilai-nilai tersebut. Selagi dua nilai boleh ditukar kepada interface{} dan masih boleh diperiksa untuk kesamaan dengan ==, ia akan bertindak seperti yang dijangkakan. Ambil perhatian bahawa anda boleh menggunakan parameter untuk tatasusunan, tetapi ia mestilah []interface{}.

Rujuk juga kepada rbac_model_matcher_using_in_op, keyget2_model, dan keyget_model.

Contoh:

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

Penilaian Ekspresi

Penilaian pencocokan dalam Casbin dilaksanakan oleh penilai ekspresi dalam setiap bahasa. Casbin menggabungkan kekuatan mereka untuk menyediakan bahasa PERM yang seragam. Selain sintaks model yang diberikan di sini, penilai ekspresi ini mungkin menawarkan fungsi tambahan yang mungkin tidak didukung oleh bahasa atau implementasi lain. Harap berhati-hati ketika menggunakan fungsi ini.

Penilai ekspresi yang digunakan oleh setiap implementasi Casbin adalah sebagai berikut:

ImplementasiBahasaPenilai Ekspresi
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
nota

Jika anda menghadapi masalah prestasi dengan Casbin, ia mungkin disebabkan oleh kekurangan kecekapan penilaian ungkapan. Anda boleh menangani isu ini kepada Casbin atau penilaian ungkapan terus untuk mendapatkan nasihat tentang mempercepatkan prestasi. Untuk maklumat lanjut, sila rujuk bahagian Penanda Aras.