0

私はこのケーキphpaclモデルの記事に従って、独自のacl実装を作成しています。

ACOAROとACO_AROの概念を理解しました。aroがacoにアクセスできるかどうかを判断するCheckメソッドを実装したいと思います。AROツリーとACOツリーがあるので、acoからaroへの最も効果的な権限を計算するにはどうすればよいですか。

また、checkメソッドが実装されているが、 phpaclの実装にある以下の記事を見つけました

要するに、何が優先されるべきかアカウントまたはグループ、acoまたは親aco。

この記事のようなもの

今まで更新私はここまで到達しました

次のようにaccessControlEntryクラスを作成しました

public class AccessControlEntry
{
    public BsonObjectId AccessControlEntryId { get; set; }
    public BsonObjectId AccessRequestObjectId { get; set; }
    public BsonObjectId AccessControlObjectId { get; set; }
    public bool CanView { get; set; }
    public bool CanEdit { get; set; }
    public bool CanDelete { get; set; }
    public bool CanAdministrate { get; set; }
}

        public bool Check(Usercontext usercontext, BsonObjectId acoId, string permission)
    {
        //aco id is accessControlObjectId like in cakephp acl
        Account acc = _usercontextService.GetAccountByUserContext(usercontext);

        //getting ACE  eg X account has CanRead=true on Y object
        AccessControlEntry entry = _accessControlEntryRepository.GetAccessControlEntry(acc.AccountId, acoId);
        if (entry != null)
        {
            bool value = (bool)entry.GetType().GetProperty(permission).GetValue(entry, null);
            return value;
        }

        //account entry not found ...search in groups
        bool groupEntryFound = false;
        bool effectiveValue = false;
        Group[] groups = _usercontextService.GetGroupsForAccount(acc.AccountId);
        foreach (Group group in groups)
        {
            AccessControlEntry entryGroup = _accessControlEntryRepository.GetAccessControlEntry(group.GroupId, acoId);
            if (entryGroup != null)
            {
                groupEntryFound = true;
                effectiveValue |= (bool)entryGroup.GetType().GetProperty(permission).GetValue(entryGroup, null);
            }
        }

        //ACE found in group ..return most privilged value
        if (groupEntryFound)
            return effectiveValue;

        //entry not found for account nor for group..return false
        return false;
    }

私はこれのように他のサービスからcheckメソッドを呼び出します

Check(context,44556,"CanRead")

checkメソッドは、アカウントのAccessControlEntryを検索し、アカウントのエントリが見つからない場合は、グループを検索します。

4

4 に答える 4

0

上記の情報があれば、いくつかの簡単なツールを作成できます。私の場合、コンテンツ管理システムを使用しているため、ACL はページ アクセスに関するものです。

最初に、ACL エントリがどのように見えるかを定義します...

using System;
namespace Core.Objects.CMS
{
    /// <summary>
    /// Represents a record on an access control list
    /// </summary>
    public class PageACLEntry
    {
        /// <summary>
        /// Gets or sets the access control entry id.
        /// </summary>
        /// <value>
        /// The access control entry id.
        /// </value>
        public int PageACLEntryId { get; set; }
        /// <summary>
        /// Gets or sets the page id.
        /// </summary>
        /// <value>
        /// The page id.
        /// </value>
        public int PageId { get; set; }
        /// <summary>
        /// Gets or sets the name of the role.
        /// </summary>
        /// <value>
        /// The name of the role.
        /// </value>
        public string RoleName { get; set; }
        /// <summary>
        /// Gets or sets the read.
        /// </summary>
        /// <value>
        /// The read.
        /// </value>
        public bool? Read { get; set; }
        /// <summary>
        /// Gets or sets the content of the update.
        /// </summary>
        /// <value>
        /// The content of the update.
        /// </value>
        public bool? UpdateContent { get; set; }
        /// <summary>
        /// Gets or sets the update meta.
        /// </summary>
        /// <value>
        /// The update meta.
        /// </value>
        public bool? UpdateMeta { get; set; }
        /// <summary>
        /// Gets or sets the delete.
        /// </summary>
        /// <value>
        /// The delete.
        /// </value>
        public bool? Delete { get; set; }
        /// <summary>
        /// Gets or sets the full control.
        /// </summary>
        /// <value>
        /// The full control.
        /// </value>
        public bool? FullControl { get; set; }
    }
}

次に、評価を処理するヘルパー クラスを作成します ...

using System.Collections.Generic;
using System.Security.Principal;
using Core.Objects.CMS;

namespace Core.Utilities
{
    /// <summary>
    /// Tools for permission calculation
    /// </summary>
    public static class PermissionHelper
    {
        /// <summary>
        /// Calculates the page permissions the given user has on the given page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>the effective permissions</returns>
        private static PageACLEntry CalculatePagePermissions(Page page, IPrincipal user)
        {
            PageACLEntry result = new PageACLEntry();
            // start with acl for the current page
            List<PageACLEntry> acl = new List<PageACLEntry>(page.AclRules);
            // append all the way up the tree until parent == null
            acl = AppendTreePermissions(acl, page, user);
            // reverse the list so we evaluate root first then work up to here
            acl.Reverse();
            // because of the order in which these are applied the most local rules overrule the less local
            // the wider the scope the less it applies
            acl.ForEach(ace => 
            {
                // only apply rules that apply to roles that our current user is in
                if (user.IsInRole(ace.RoleName))
                {
                    result.Read = Eval(result.Read, ace.Read);
                    result.Delete = Eval(result.Delete, ace.Delete);
                    result.UpdateMeta = Eval(result.UpdateMeta, ace.UpdateMeta);
                    result.UpdateContent = Eval(result.UpdateContent, ace.UpdateContent);
                    result.FullControl = Eval(result.FullControl, ace.FullControl);
                }
            });

            return result;
        }

        /// <summary>
        /// Evaluates the specified permission level.
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="suggestion">The suggestion.</param>
        /// <returns>evaluation result</returns>
        private static bool? Eval(bool? target, bool? suggestion)
        {
            bool? result = null; 
            switch (target)
            { 
                case false:
                    result = false;
                    break;
                case true:
                    result = true;
                    break;
                case null:
                    break;
            }

            return result;
        }

        /// <summary>
        /// Appends the tree acl from the tree root up to this point.
        /// </summary>
        /// <param name="acl">The acl.</param>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>the complete acl</returns>
        private static List<PageACLEntry> AppendTreePermissions(List<PageACLEntry> acl, Page page, IPrincipal user)
        {
            Page currentPage = page.Parent;
            while (currentPage != null)
            {
                acl.AddRange(currentPage.AclRules);
                currentPage = page.Parent;
            }

            return acl;
        }

        /// <summary>
        /// Determines if the current User can read the given page.
        /// Unless an explicit deny rule is in place the default is to make everything read only.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>
        /// access right indication as bool
        /// </returns>
        public static bool UserCanRead(Page page, IPrincipal user)
        {
            PageACLEntry permissions = CalculatePagePermissions(page, user);
            if (permissions.Read != false)
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// Determines if the current User can delete the given page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>
        /// access right indication as bool
        /// </returns>
        public static bool UserCanDelete(Page page, IPrincipal user)
        {
            PageACLEntry permissions = CalculatePagePermissions(page, user);

            if (permissions.FullControl == true || permissions.Delete == true)
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// Determines if the current User can update the given page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>
        /// access right indication as bool
        /// </returns>
        public static bool UserCanUpdate(Page page, IPrincipal user)
        {
            PageACLEntry permissions = CalculatePagePermissions(page, user);

            if (permissions.FullControl == true || permissions.UpdateMeta == true)
            {
                return true;
            }

            return false;
        }
        public static bool UserCanUpdateContent(Page page, IPrincipal user)
        {
            PageACLEntry permissions = CalculatePagePermissions(page, user);

            if (permissions.FullControl == true || permissions.UpdateContent == true)
            {
                return true;
            }

            return false;
        }
        /// <summary>
        /// Determines if the current User can append children to the given page.
        /// </summary>
        /// <param name="page">The page.</param>
        /// <param name="user">The user.</param>
        /// <returns>
        /// access right indication as bool
        /// </returns>
        public static bool UserCanAddChildTo(Page page, IPrincipal user)
        {
            PageACLEntry permissions = CalculatePagePermissions(page, user);

            if (permissions.FullControl == true || permissions.UpdateMeta == true)
            {
                return true;
            }

            return false;
        }
    }
}

これで、ページと IPrincipal オブジェクトを渡すだけですべての制御が可能になり、アクセスのレベルを表す ACLEntry が返されます。

私は、Calculation メソッドを非公開にし、CanX メソッドのみを公開することで、セキュリティの実装をさらに抽象化することにしました。

だから今は次のように簡単です

bool result = PermissionsHelper.UserCanRead(page, user);

たくさんのコードがあるように見えますが、(コーディング基準を満たすために) 書式設定とコメントを取り除くと、実際にはコードはほとんどありません。これを Visual Studio のクラス ファイルにコピーすると、実際には非常に簡単に理解できます。維持。

また、データを取得するためにリポジトリまたはサービス クラスを一度も渡さないことに注意してください。これは、これを使用して、コード ファースト EF モデリングを使用して記述されたオブジェクトを構築し、遅延読み込みを使用しているためです。ツリーをクロールするために、page.parent.AClEntries より少し多くなります。

ああ、あなたがそれを必要とする場合に備えて、ここに私のページクラスがあります...

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Core.Objects.CMS
{
    /// <summary>
    /// Represents a managed CMS page
    /// </summary>
    [Table("Pages")]
    public class Page
    {
        /// <summary>
        /// Gets or sets the page id.
        /// </summary>
        /// <value>
        /// The page id.
        /// </value>
        public int PageId { get; set; }
        /// <summary>
        /// Gets or sets the version.
        /// </summary>
        /// <value>
        /// The version.
        /// </value>
        public int Version { get; set; }
        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        /// <value>
        /// The title.
        /// </value>
        public string Title { get; set; }
        /// <summary>
        /// Gets or sets the template.
        /// </summary>
        /// <value>
        /// The template.
        /// </value>
        public string Template { get; set; }
        /// <summary>
        /// Gets or sets the path.
        /// </summary>
        /// <value>
        /// The path.
        /// </value>
        public string Path { get; set; }
        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        /// <value>
        /// The parent.
        /// </value>
        public virtual Page Parent { get; set; }
        /// <summary>
        /// Gets or sets the children.
        /// </summary>
        /// <value>
        /// The children.
        /// </value>
        public virtual List<Page> Children { get; set; }
        /// <summary>
        /// Gets or sets the content.
        /// </summary>
        /// <value>
        /// The content.
        /// </value>
        public virtual List<PageContent> Content { get; set; }
        /// <summary>
        /// Gets or sets the component stacks.
        /// </summary>
        /// <value>
        /// The component stacks.
        /// </value>
        public virtual List<Stack> ComponentStacks { get; set; }
        /// <summary>
        /// Gets or sets the acl rules.
        /// </summary>
        /// <value>
        /// The acl rules.
        /// </value>
        public virtual List<PageACLEntry> AclRules { get; set; }
    }
}

非常に単純な poco ... EF の機能を使用して、オンデマンドの SQL クロールをすべて実行します。1つの欠点...ツリーに深くネストされたページがある場合、特に効率的であるとは思えません。

これを改善するための提案はまだ受け付けていますが、これは当時、管理可能なソリューションを実装する最もクリーンな方法のように感じました. これで、問題を完全に可視化して、効率を向上させることができます。

しかし、少なくともあなたには基準点があります:)

于 2012-07-31T21:55:29.983 に答える
0

このURLを参照してください。これはcakephp 2.0です:-

http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/simple-acl-controlled-application.html

http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/part-two.html
于 2012-07-29T20:11:56.877 に答える
0

コンテンツ管理システム/ドキュメント管理システム モデルを実装しているときに、.Net で同じ問題が発生しました。

最も単純な形式では実質的に 2 つのツリーがあり、継承されたアクセス許可に基づいてオンザフライで「有効なアクセス許可」の計算を行うことは、スケーラビリティの点でアプリにとって不健康ですが、それが不可能というわけではありません。

これは、モデルを単純化するためだけに、基本的に現在のノードに基づいて有効なアクセス許可を計算できることを意味します。

例: (「ページ」をノードとして使用します)

ユーザーがページ 4 に対して持っているアクセス許可を把握するための複雑なモデルでは、ページ 1、3、および 4 に割り当てられたすべてのアクセス許可を効果的に取得してから、「追加マージ」を実行します。

単純化されたモデルでは、ページ 4 のユーザーに追加された権限のみを考慮します。

   Page 1
      Page 2 
      Page 3
        Page 4

問題をできるだけ単純にして、バグをできるだけなくすために、関連する acl エントリをツリー ノードに追加できるのはロール/グループだけであるモデルを採用することにしました。

これは、次のようなクエリを効果的に実行するアクセス許可に関して何が必要かを把握することを意味していました (seudo コードのみの実装は異なる場合があります)。

var allAcls = "Select all ACL where PageId in (pagesToThisPoint) and Role in (userRoles)" 
var resultAcl = new aclEntry();

allAcls.Each(acl => {
  resultAcl.Delete = (acl.Delete > resultAcl.Delete ? acl.Delete : resultAcl.Delete);
  resultAcl.Update = (acl.Update > resultAcl.Update ? acl.Update : resultAcl.Update);
  resultAcl.Read = (acl.Read > resultAcl.Read ? acl.Read : resultAcl.Read);
         ....
});

ルールが拒否ルールである場合、一般的な規則は、許可ルールを上書きするというものです。

そのため、ループをもう一度繰り返して、拒否を評価します。

allAcls.Each(acl => {
  resultAcl.Delete = (acl.Delete == deny ? resultAcl.Delete == deny);
  resultAcl.Update = (acl.Update == deny ? resultAcl.Update == deny);
  resultAcl.Read = (acl.Read == deny ? resultAcl.Read == deny);
         ....
});

したがって、基本的には、ユーザーとページの両方のすべてのロールを取得すると言っています。ページには、これらのロールのいずれかの acl エントリがあり、それを結果のアクセス許可に追加してから、明示的な拒否が定義されているアクセス許可を削除します。

現在のページの現在のユーザーに適用されるすべての権限と一致するユーザー固有の権限のプロセスを再実行し、役割ベースのセットを上書きする場合は、さらに拡張できると確信しています。

一般的な経験則として、私は、ルールが具体的であるほど関連性が高いという論理に従う傾向があります。

すべての管理者はサイト全体にアクセスできます 管理者は Web サイトの管理セクションに対するすべての権限を拒否されます すべてのセールスはセールス セクションにアクセスできます すべてのマーケティングはマーケティングにアクセスできます マーケティング ユーザー「Bob」はセールスにアクセスできます

上記のロジックは、これらすべてをカバーし、次のように効果的にアクセスを適用します: ユーザーは自分の部門のセクションへの権限を取得します (営業ユーザー = 営業など) マネージャーは追加の権限を取得し、すべての領域へのアクセスが管理者を受け入れます (おそらく IT のみ?) ボブは私たちの例外であり、彼はマーケティングに携わっていますが、私たちは彼に販売の権利を与えています.

これが意味すること: 1. ユーザーをロールに追加できます 2. ページをロールに追加でき、問題のロールに「acl」権限が与えられます これは、次のように言えます: ユーザーが販売ロールにいる場合、それらを付与します「読み取り、更新」 3. 定義上、ページ自体は「ロール内」ではなく、ロールに付与するアクセス権の量を知っているだけです 4. このモデルを拡張すると、特定のユーザーの ACL エントリを指定できるようになります 5. ユーザー ACL エントリロール acl エントリを上書きします 6. 考慮される ACL エントリは、この時点までのツリー全体のものです 7. 拒否ルールは許可ルールを上書きします

では、親ページに「販売ユーザーは完全にアクセスを拒否されています」と表示されていて、現在のページに「現在のユーザー bob にはフル アクセス権があります」と表示されている場合はどうなるでしょうか。

これは、開発者/ビジネスがそのようなシナリオをどのように扱うかについての選択に基づいています...

私の考えは次のとおりです。ユーザーはロールよりもスコープがローカルです。拒否ルールは親に適用されますが、許可ルールはページに適用されます。許可ルールを取ります。

ただし、Parent ルールがユーザー用で、ロールの Page ルールが現在のページ用である場合、同じロジックを使用してロールのルールを取得します。

この ACL の多くは主観的なものです。私は、人々が慣れ親しんでいるものに頼る傾向があります。将来的に20の質問を取得することから。

とにかくほとんど。

于 2012-07-28T13:07:15.923 に答える
0

PHPGaclから多くのことを学びました。現在は少し古いプロジェクトですが、コンセプトは今日でも完全に有効です。

彼らのマニュアルは、基本的なことからより複雑な問題まで、すべてを理解するのに役立ちました。

于 2012-07-31T14:44:39.660 に答える