Skip to content

Casbin

公式リポジトリ:casbin/casbin: An authorization library that supports access control models like ACL, RBAC, ABAC in Golang (github.com)

公式ドキュメント:概述 | Casbin

TIP

この記事は Casbin の入門記事です。より詳しく知りたい方は公式サイトをご覧ください。

紹介

システムにおいて、バックエンド開発者は API 権限管理を担当する必要がありますが、これには多くの作業が必要です。もしすべてのプロジェクトで毎回手書きする必要があるなら、多くの時間を浪費することになります。より多くの人的資源と物的資源を持つ大企業は、独自の権限フレームワークを開発する傾向がありますが、中小企業の多くはこの開発コストを負担できません。そのため、市場に出回っているオープンソースの権限フレームワークが彼らの首选となります。Casbin はまさにそのような効率的なオープンソースのアクセス制御ライブラリです。Go 言語で開発されており、他の主要言語もサポートしています。

注意すべき点は、Casbin はアクセス制御フレームワークであり、アクセス制御のみを担当し、アクセス認証のロジックは Casbin が担当しないことです。Casbin はユーザーとロール間のマッピング関係のみを保存します。以下のアクセス制御モデルをサポートしています:

  1. ACL (Access Control List, アクセス制御リスト)
  2. スーパーユーザー付き ACL
  3. ユーザーなしの ACL: 認証やユーザーログインがないシステムに特に有効です。
  4. リソースなしの ACL: 特定のシナリオでは、個々のリソースではなくリソースのタイプのみを対象とします。例えば write-articleread-log などの権限です。特定の論文やログへのアクセスは制御しません。
  5. RBAC (ロールベースアクセス制御)
  6. リソースロールをサポートする RBAC: ユーザーとリソースは同時にロール(またはグループ)を持つことができます。
  7. ドメイン/テナントをサポートする RBAC: ユーザーは異なるドメイン/テナントに対して異なるロールセットを設定できます。
  8. ABAC (属性ベースアクセス制御): resource.Owner のような構文を使用して要素の属性を取得することをサポートします。
  9. RESTful: /res/*/res/:id などのパスや、GETPOSTPUTDELETE などの HTTP メソッドをサポートします。
  10. 拒否優先: 許可と拒否の両方の認証をサポートし、拒否は許可より優先されます。
  11. 優先度: ポリシールールは先後順序に従って優先度を決定します。ファイアウォールルールに似ています。

動作原理

Casbin では、アクセス制御モデルは PERM ベースの設定ファイルに抽象化されます。PERM は Policy(ポリシー)、Effect(効果)、Request(リクエスト)、Matcher(マッチャー)を指します。プロジェクトで認可メカニズムを変更する場合は、設定ファイルを簡単に変更するだけです。通常の Model 設定ファイルの内容は以下の通りです:

bash
[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, act

p は policy を指し、他の文字で置き換えることはできません。sub は subject でポリシー主体、obj は object でポリシー対象、act は action でアクションを指します。

p = sub, obj, act

4 番目のフィールド eft を持つこともできます。省略された場合、デフォルトで eft は allow となります。

p=sub, obj, act, eft

この行はポリシーの書き方を定義するだけで、具体的なポリシー定義ではありません。以下は具体的なポリシーの例です:

p, jojo, cake, eat

p はこれがポリシー定義であることを示し、jojo はポリシー主体、cake はポリシー対象、eat はアクションを指し、完全な意味は主体 jojo が対象 cake に対してアクション eat を実行できることです。具体的なポリシー定義はモデルファイルには表示されず、専用のポリシーファイルまたはデータベースに保存されます。

リクエスト

設定ファイルにおいて、リクエスト定義部分は以下の通りです:

[request_definition]
r = sub, obj, act

r は request を指し、他の文字で置き換えることはできません。sub は subject でリクエスト主体、obj は object でリクエスト対象、act は action でリクエストアクションを指します。通常、リクエスト定義とポリシー定義のフィールド名は一致します。リクエスト部分は Casbin が担当せず、開発者が何をリクエスト主体とし、何をリクエスト対象とするかを決定します。Casbin は传入されたフィールドに基づいてアクセス制御を行うだけです。

マッチング

設定ファイルにおいて、マッチング定義部分は以下の通りです:

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

m は matcher を指し、他の文字で置き換えることはできません。その後には対応するマッチングルールのが続き、上記はシンプルなブール式で、传入されたリクエストのすべてのフィールドがポリシー定義のフィールドと完全に一致すればマッチします。もちろん、ワイルドカードや表現力の高い正規表現を使用することもできます。

さらに、matcher は in 構文もサポートしています。例えば:

[matchers]
m = r.sub in ("root","admin")

または:

[matchers]
m = r.sub.Name in (r.obj.Admins)
go
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-overrideACL, RBAC など
!some(where (p.eft == deny))deny-override拒否オーバーライド
some(where (p.eft == allow)) && !some(where (p.eft == deny))allow-and-deny許可と拒否
priority(p.eft) || denypriority優先度
subjectPriority(p.eft)ロールベースの優先度主題優先度

TIP

  1. 上記の 4 つの定義は複数定義でき、構文は type+number です。例えば r2p2e2m2

  2. モデルファイルにはコメントを付けることができ、# 記号でコメントします。

以下はモデルファイルの動作プロセスを示す例です。まず、シンプルな 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_admin

alice は主体を指し、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_group

g2 はリソースロールグループを定義し、リソースを異なるロールに割り当て、ユーザーロールとリソースロール間のユーザー関係を規定します。

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 ロールを持つことを定義します。

ABAC

Golang学习网由www.golangdev.cn整理维护