주요 콘텐츠로 건너뛰기

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

정책의 각 줄은 정책 규칙이라고 불립니다. 각 정책 규칙은 policy type으로 시작합니다, 예를 들어 p 또는 p2. 여러 정의가 있을 경우 정책 정의와 일치하는 데 사용됩니다. 위의 정책은 다음과 같은 바인딩을 보여줍니다. 바인딩은 매처에서 사용할 수 있습니다.

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

정책 규칙의 요소는 항상 문자열로 간주됩니다. 이에 대해 궁금한 점이 있다면, 다음 토론을 참조하십시오: 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에 대한 일치하는 정책 규칙이 있어서는 안된다는 것을 의미합니다. 따라서 이런 방식으로, allow와 deny 권한이 모두 지원되며, 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

다중 섹션 유형

여러 정책 정의 또는 여러 매처가 필요한 경우, p2 또는 m2를 예로 사용할 수 있습니다. 사실, 위에서 언급한 네 가지 섹션 모두 다중 유형을 사용할 수 있으며, 문법은 r 다음에 숫자가 오는 것입니다, 예를 들어 r2 또는 e2. 기본적으로, 이 네 가지 섹션은 일대일로 대응해야 합니다. 예를 들어, r2 섹션은 m2 매처를 사용하여 p2 정책을 매치합니다.

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" 연산자를 사용할 수도 있습니다. 이 연산자는 오른쪽의 배열을 확인하여 왼쪽의 값과 같은 값을 포함하는지 확인합니다. 동등성은 == 연산자를 사용하여 결정되며, 이 라이브러리는 값 사이의 유형을 확인하지 않습니다. 두 값이 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 또는 표현식 평가기에 직접 문제를 제기할 수 있습니다. 자세한 내용은 벤치마크 섹션을 참조하십시오.