Casbin
公式ドキュメント:概述 | Casbin
TIP
この記事は Casbin の入門記事です。より詳しく知りたい方は公式サイトをご覧ください。
紹介
システムにおいて、バックエンド開発者は API 権限管理を担当する必要がありますが、これには多くの作業が必要です。もしすべてのプロジェクトで毎回手書きする必要があるなら、多くの時間を浪費することになります。より多くの人的資源と物的資源を持つ大企業は、独自の権限フレームワークを開発する傾向がありますが、中小企業の多くはこの開発コストを負担できません。そのため、市場に出回っているオープンソースの権限フレームワークが彼らの首选となります。Casbin はまさにそのような効率的なオープンソースのアクセス制御ライブラリです。Go 言語で開発されており、他の主要言語もサポートしています。
注意すべき点は、Casbin はアクセス制御フレームワークであり、アクセス制御のみを担当し、アクセス認証のロジックは Casbin が担当しないことです。Casbin はユーザーとロール間のマッピング関係のみを保存します。以下のアクセス制御モデルをサポートしています:
- ACL (Access Control List, アクセス制御リスト)
- スーパーユーザー付き ACL
- ユーザーなしの ACL: 認証やユーザーログインがないシステムに特に有効です。
- リソースなしの ACL: 特定のシナリオでは、個々のリソースではなくリソースのタイプのみを対象とします。例えば
write-article、read-logなどの権限です。特定の論文やログへのアクセスは制御しません。 - RBAC (ロールベースアクセス制御)
- リソースロールをサポートする RBAC: ユーザーとリソースは同時にロール(またはグループ)を持つことができます。
- ドメイン/テナントをサポートする RBAC: ユーザーは異なるドメイン/テナントに対して異なるロールセットを設定できます。
- ABAC (属性ベースアクセス制御):
resource.Ownerのような構文を使用して要素の属性を取得することをサポートします。 - RESTful:
/res/*、/res/:idなどのパスや、GET、POST、PUT、DELETEなどの HTTP メソッドをサポートします。 - 拒否優先: 許可と拒否の両方の認証をサポートし、拒否は許可より優先されます。
- 優先度: ポリシールールは先後順序に従って優先度を決定します。ファイアウォールルールに似ています。
動作原理
Casbin では、アクセス制御モデルは PERM ベースの設定ファイルに抽象化されます。PERM は Policy(ポリシー)、Effect(効果)、Request(リクエスト)、Matcher(マッチャー)を指します。プロジェクトで認可メカニズムを変更する場合は、設定ファイルを簡単に変更するだけです。通常の Model 設定ファイルの内容は以下の通りです:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actこれは最もシンプルな ACL アクセス制御モデルです。
ポリシー
設定ファイルにおいて、ポリシー定義部分は以下の通りです:
[policy_definition]
p = sub, obj, actp は policy を指し、他の文字で置き換えることはできません。sub は subject でポリシー主体、obj は object でポリシー対象、act は action でアクションを指します。
p = sub, obj, act4 番目のフィールド eft を持つこともできます。省略された場合、デフォルトで eft は allow となります。
p=sub, obj, act, eftこの行はポリシーの書き方を定義するだけで、具体的なポリシー定義ではありません。以下は具体的なポリシーの例です:
p, jojo, cake, eatp はこれがポリシー定義であることを示し、jojo はポリシー主体、cake はポリシー対象、eat はアクションを指し、完全な意味は主体 jojo が対象 cake に対してアクション eat を実行できることです。具体的なポリシー定義はモデルファイルには表示されず、専用のポリシーファイルまたはデータベースに保存されます。
リクエスト
設定ファイルにおいて、リクエスト定義部分は以下の通りです:
[request_definition]
r = sub, obj, actr は request を指し、他の文字で置き換えることはできません。sub は subject でリクエスト主体、obj は object でリクエスト対象、act は action でリクエストアクションを指します。通常、リクエスト定義とポリシー定義のフィールド名は一致します。リクエスト部分は Casbin が担当せず、開発者が何をリクエスト主体とし、何をリクエスト対象とするかを決定します。Casbin は传入されたフィールドに基づいてアクセス制御を行うだけです。
マッチング
設定ファイルにおいて、マッチング定義部分は以下の通りです:
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actm は matcher を指し、他の文字で置き換えることはできません。その後には対応するマッチングルールのが続き、上記はシンプルなブール式で、传入されたリクエストのすべてのフィールドがポリシー定義のフィールドと完全に一致すればマッチします。もちろん、ワイルドカードや表現力の高い正規表現を使用することもできます。
さらに、matcher は in 構文もサポートしています。例えば:
[matchers]
m = r.sub in ("root","admin")または:
[matchers]
m = r.sub.Name in (r.obj.Admins)e.Enforce(Sub{Name: "alice"}, Obj{Name: "a book", Admins: []interface{}{"alice", "bob"}})マッチング時、Casbin は型チェックを行わず、interface として == で等しいかどうかをチェックします。
効果
効果定義部分はマッチング結果に対して再度論理組合せ判断を行います。設定ファイルにおいて、効果定義部分は以下の通りです:
[policy_effect]
e = some(where (p.eft == allow))e は effect を指し、他の文字で置き換えることはできません。some 量詞はマッチャーを満たすポリシー定義が存在するかどうかを判断します。any 量詞はすべてのポリシー定義がマッチャーを満たすかどうかを判断します。
some(where (p.eft == allow))このルールは、マッチング結果に allow の結果が 1 つあれば、最終結果は allow となります。
e = !some(where (p.eft == deny))このルールは、マッチング結果に deny の結果が存在しなければ、最終結果は allow となります。
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))このルールは、マッチング結果に allow が 1 つあり、deny の結果が存在しなければ、最終結果は allow となります。
Casbin は上記のポリシー効果の構文を設計していますが、実際の実装はハードコードされたポリシー効果を使用しています。この柔軟性はあまり必要ないと考えています。現在、内蔵のポリシー効果を使用する必要があり、カスタマイズはできません。内蔵でサポートされているポリシー効果は以下の通りです。
| ポリシー効果定義 | 意味 | 例 |
|---|---|---|
| some(where (p.eft == allow)) | allow-override | ACL, RBAC など |
| !some(where (p.eft == deny)) | deny-override | 拒否オーバーライド |
| some(where (p.eft == allow)) && !some(where (p.eft == deny)) | allow-and-deny | 許可と拒否 |
| priority(p.eft) || deny | priority | 優先度 |
| subjectPriority(p.eft) | ロールベースの優先度 | 主題優先度 |
TIP
上記の 4 つの定義は複数定義でき、構文は
type+numberです。例えばr2、p2、e2、m2。モデルファイルにはコメントを付けることができ、
#記号でコメントします。
例
以下はモデルファイルの動作プロセスを示す例です。まず、シンプルな ACL モデルファイルを以下のように定義します:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.actポリシーファイルは以下の通りです:
p, alice, data1, read
p, bob, data2, write主体、対象、アクションをどのように抽出するかはビジネスロジックによって決定されますが、ここでは重要ではないので省略します。以下に最もシンプルな方法で传入されたリクエストを示します:
alice, data1, read
bob, data1, read
alice, data2, write
bob, data2, writeポリシーファイルでは、alice が data1 に対して read 操作を行う権限を持ち、bob が data2 に対して write 操作を行う権限を持つと定義されています。传入されたリクエストにおいて:
alice, data1, readは alice が data1 に対して read 操作を実行したいことを示し、
bob, data1, readは bob が data1 に対して read 操作を実行したいことを示し、残りも同様です。最終結果は以下の通りです:
true
false
false
trueこれは最もシンプルな ACL の例です。Casbin 公式サイトではオンラインで編集してテストできます。Casbin editor でテストしてください。
RBAC
RBAC(Role-Based-Access-Controll)は、ロールベースのアクセス制御で、ACL モデルよりも [role definition] が 1 つ増えます。以下はシンプルな RBAC モデルです:
[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ロールの定義は以下の通りです:
[role_definition]
g = _, _g は group を指し、他の文字で置き換えることはできません。type+number 方式で複数作成でき、_ はプレースホルダーで、いくつの引数があるかを示します。一般的に、ポリシーでは g は以下の形式になります:
g, alice, data2_admin
g, mike, data1_admin
g, data1_admin data2_adminalice は主体を指し、data2_admin はロールを指します。厳密に言えば、Casbin はこれらを文字列として扱い、その意味と使用方法は開発者次第です。
g, alice, data2_adminは alice が data2_admin ロールを持つことを示します。
g, mike, data1_adminは mike が data1_admin ロールを持つことを示します。
g, data1_admin data2_adminはロール data1_admin が data2_admin ロールを持つことを示します。これはロール間の継承関係です。
リソースロールモデル
リソースロールモデルは g2 を新たに追加し、リソースのロール定義を行います。モデル定義は以下の通りです:
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
g2 = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.actポリシーの例は以下の通りです:
p, alice, data1, read
p, bob, data2, write
p, data_group_admin, data_group, write
g, alice, data_group_admin
g2, data1, data_group
g2, data2, data_groupg2 はリソースロールグループを定義し、リソースを異なるロールに割り当て、ユーザーロールとリソースロール間のユーザー関係を規定します。
p, data_group_admin, data_group, writeこのポリシーは、data_group_admin ロールを持つユーザーが data_group ロールを持つリソースに対して書き込み操作を実行できることを定義します。
マルチテナントドメインモデル
[request_definition]
r = sub, dom, obj, act
[policy_definition]
p = sub, dom, obj, act
[role_definition]
g = _, _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.actマルチテナントドメインモデルは、従来の RBAC モデルに比べて dom フィールドが追加されており、主体が属するドメインを示すために使用されます。ポリシーの例は以下の通りです:
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write
g, alice, admin, domain1
g, bob, admin, domain2例えば:
p, admin, domain1, data1, readは、domain1 ドメインに属する主体 admin が data1 に対して read 操作を行う権限を持つことを定義します。
g, alice, admin, domain1は、alice が domain1 に属し、admin ロールを持つことを定義します。
