CasbinとPERMを使用した柔軟な承認。実用例

PERM言語とCasbinライブラリに関する前回の記事を書いた後質問が発生しましたそして、一人だけでなく、コメントで最初に答えたかったのですが、資料の量が通常のコメントを超えていることに気づいたので、別の記事の形でこの答えを提示します。







長い間、質問者の頭の中にある具体的な構成が理解できませんでしたが、最終的には質問を明確にした後、回答を受け取り、それをまとめて引用します。







そして、そのようなDSLで問題はどのように解決されますか?「私が見ることができるオブジェクトのリストを表示しますか?データベースからすべてのレコードを掻き出すのではなく、何らかの方法でこれをSQLクエリに変換する必要があります。



サイトには何かのリストを表示するインターフェースがあります。たとえば、CMS管理領域の記事です。データベースには何万もの記事がありますが、通常、ユーザーは1ダースしかアクセスできません。特定のユーザーに表示される記事をデータベースから取得するにはどうすればよいですか?さて、誰もが見ることができるすべてのルールがある場合-コードから何らかのDSLに取り出されますか?

言い換えると、



select *

fromarticlesのようなクエリを作成する方法 はr.userId = currentUserIdの結合ロールrです。ここでarticle.owner

= currentUserId

OR(r.role in ['admin'、 'supevisor'])-合計の管理者

OR(r.domain = currentDomainId AND r.role in ['domain-admin'、 'domain-supervisor'])-管理者ドメイン



コードにはLINQ式の形式でそのようなルールがあり、この問題を解決できます。そして、そのようなタスクは、「メモリからアンロードされた1つのオブジェクトへのアクセスがあるかどうかを確認する」よりもさらに頻繁に発生します。

この構造を正しく理解し、リバースリバースエンジニアリング中に、この問題を解決するための初期データを引き出すことができたと思います。まず、マルチテナンシー(ドメイン)はタスクを複雑にし、それに応じて理解を複雑にするため、使用を省略します。前回の記事でそれらの使用例を示しました。







, , , Casbin.









CMS, . user



.       , admin



supervisor



. supervisor



, admin



supervisor



, , .







, :



CMS:

DBテーブルスキーマ







Users:

ユーザーテーブルの内容







:

Roles:

ロールテーブルの内容







, Piter , Bob — . Alice , , .







Articles:

Articlesテーブルの内容







, (Piter, id=3) :







select * from articles a
left join roles r on r.userId = 3
where a.owner = 3
OR (r.role in ('admin', 'supevisor'))
      
      





管理者向けのサンプル結果







(Bob, id=2) :







select * from articles a
left join roles r on r.userId = 2
where a.owner = 2
OR (r.role in ('admin', 'supevisor'))
      
      





スーパーバイザーのサンプル結果







(Alice, id=1) :







select * from articles a
left join roles r on r.userId = 1
where a.owner = 1
OR (r.role in ('admin', 'supevisor'))
      
      





ユーザーのサンプル結果







, Casbin.







Casbin



PERM — , .

.. , () . ( Id=1 ).







, , — RBAC.

RBAC , . RBAC user



, author



user



(.. ), , admin



.

, , . user



supervisor



admin



, — , . , user



, . admin



supervisor



, .

RBAC, , -, , .

: RBAC vs. ABAC







, (user



, supervisor



,admin



) — —



. , . , , — .







" "



RBAC (rbac_model.conf



), :







[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
      
      





, Roles. . *.csv



, . cvs rbac_policy.csv



:







p, user, article, read
p, user, article, modify
p, user, article, create
p, user, article, delete

g, supervisor, user
g, admin, supervisor

g, 1, user
g, 2, supervisor
g, 3, admin
      
      





, user



, , . supervisor



user.



admin



supervisor



.

alice(1) user



, bob(2) supervisor



, piter(3) — admin



.

, , .







, . cross-cutting concern CQRS+MediatR







public IList<Article> GetArticlesForAdminPanel(int currentUserId)
{
    var e = new Enforcer("CasbinConfig/rbac_model.conf", "CasbinConfig/rbac_policy.csv");

    var obj = "article";
    var act = "read";

    // ,       
    if (e.Enforce(currentUserId.ToString(), obj, act))
    {
        //   
        var currentUserRoles = e.GetRolesForUser(currentUserId.ToString());
        //,      
        var isAdmin = currentUserRoles.Any(x => x == "admin" || x == "supervisor");

        // ,   ,   ,   
        if (!isAdmin) return _context.Articles.Where(x => x.OwnerId == currentUserId).ToList();
        else return _context.Articles.ToList();
    }
    else
    {
        //  ,  
        throw new Exception("403.       ");   
    }
}
      
      





! , .







" "



. , , - . , , user



, supervisor



admin



.







, rbac_with_abac_model.conf



:







[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 = (r.sub == r.obj.OwnerId.ToString() || g(r.sub, "supervisor")) && g(r.sub, p.sub) && r.act == p.act
      
      





, [matchers]



, r.obj == p.obj



(r.sub == r.obj.OwnerId.ToString() || g(r.sub, "supervisor"))



. r.sub (id ) r.obj.OwnerId (id ) r.sub "supervisor". admin



supervisor



admin



.







, . :







public void UpdateArticle(int currentUserId, Article newArticle)
{
    var e = new Enforcer("CasbinConfig/rbac_with_abac_model.conf", "CasbinConfig/rbac_policy.csv");

    var act = "modify";

    //,       
    if (e.Enforce(currentUserId.ToString(), newArticle, act))
    {
        //,   
        _context.Articles.Update(newArticle);
        _context.SaveChanges();
    }
    else
    {
        //  ,  
        throw new Exception("403.  ");
    }
}
      
      





, e.Enforce



, Article



.







— .









- , user



, supervisor



— , admin



.

- PERM, delete_model.conf



:







[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 = (r.sub == r.obj.OwnerId.ToString() || g(r.sub, "admin")) && g(r.sub, p.sub) && r.act == p.act
      
      





, , admin



. supervisor



, .







, :







public void DeleteArticle(int currentUserId, Article deleteArticle)
{
    var e = new Enforcer("CasbinConfig/delete_model.conf", "CasbinConfig/rbac_policy.csv");

    var act = "delete";

    //,       
    if (e.Enforce(currentUserId.ToString(), deleteArticle, act))
    {
        // 
        _context.Articles.Remove(deleteArticle);
        _context.SaveChanges();
    }
    else
    {
        //  ,  
        throw new Exception("403.  ");
    }
}
      
      







, , Casbin PERM .







, , . , , .







Casbin DynamicExpresso.Core C# , Casbin .







, Casbin , , API. UI .







この記事を書くために使用し完全に機能的で自給自足のサンプルコードをGithub投稿しました。興味があり、喜んでいる場合は、ダウンロードして再生できます。







便利なリンク






All Articles