RBACの資料

75767 ワード

AOPにより実現する.NET上の完全なロールベースアクセス制御(RBAC)モデル



一.背景
  • .NETプラットフォームには完全なRBACメカニズムがない.NETのセキュリティモデル(コードアクセスセキュリティ:CAS)はRole階層に実装されているだけで、Task階層に細分化されていません.ASP.NET 2.0の多くのセキュリティメカニズム、例えばMembership、Web.Configのセキュリティ構成は、すべてRoleに対してしか設定できません.これらのセキュリティメカニズムを利用して、プログラム/コードハードコーディング(HardCode)ロールを必要とすることが多く、実行中にロールをカスタマイズする機能
  • を実現できません.
  • Windows 2000/2003に付属のAuthorization Managerは比較的完全なRBACモデルを実現しているが、一般的にはWindowsユーザーのみに適用され、手動でアクセスチェック(AccessCheckメソッド呼び出し)
  • を行う必要がある.
  • 権限チェックは汎用的な操作であり、最良の実現方法は側面向けのプログラミング(AOP)
  • である.
    二、関連テーマの紹介
  • RBACモデルの要素:ユーザー、ロール、タスク(またはアクション)(User、Role、Task)の3つのエンティティで、安定性が徐々に向上し、2つの関係があります.
  • Userは、日常管理運転時に確立する
  • である.
  • Roleは、導入/配信確立
  • です.
  • Taskは開発時確定
  • である.
  • User<->Roleは、日常的な管理実行時に確立された
  • です.
  • Role<->Taskは、導入/提供時に
  • を確立します.
  • 一般的に、Taskは固定的であり、アプリケーションと密接にバインドされており、ハードコーディングを行っても
  • には関係ない.
  • User/Role部分は比較的容易に実現できる、例えばASP.NET 2.0におけるMembershipの実現
  • 三、具体的な実現
    注:本文の中でAOPを実現する構想は主に以下の文章から来ている:Aspect oriented Programming using.NET-AOP in C#(http://www.developerfusion.co.uk/show/5307/3/)、これは私が見た、あります.NET上でAOPを実現する最も簡便/便利な方法は、原理紹介を提供するのに不便であり、Visual Studio 2005のSample Projectも提供され、その中にはSecurity CheckとLoggingのAOP機能がある.その利点は、AOPを実現すると同時に、インタフェースを確立する必要がなく(これは多くの人のやり方である)、既存のクラスで直接少量の変更を行うことで、完全なAOP機能を実現できることである.
    1.タスクを記述するAttributeを定義する
    
       
         using System;
    
    
    
    namespace BusinessLogic.Security
    
    {  ///   ///             /// 
    
     [AttributeUsage(AttributeTargets.All,AllowMultiple=false,Inherited=true)]  public sealed class Task : Attribute  {  private string _name,_description;   public string Name  {  get { return _name; }  set { _name = value; }  }   public string Description  {  get { return _description; }  set { _description = value; }  }   public Task(string name,string description)  {  _name = name;  _description = description;  }   public Task()  {  }  } }
    
    

    2. 编写权限检查的 AOP 类 SecurityAspect,完成权限检查的功能

    
    
    
       
         
    using System; using System.Diagnostics; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Contexts; using System.Runtime.Remoting.Activation; namespace BusinessLogic.Security { // internal class SecurityAspect : IMessageSink { // private IMessageSink m_next; // internal SecurityAspect(IMessageSink next) { m_next = next; } IMessageSink AOP } public class PermissionCheckProperty : IContextProperty, IContributeObjectSink { IContributeObjectSink , AOP IContextProperty } // , Consumer [AttributeUsage(AttributeTargets.Class)] public class PermissionCheckAttribute : ContextAttribute { public PermissionCheckAttribute() : base("PermissionCheck") { } public override void GetPropertiesForNewContext(IConstructionCallMessage ccm) { ccm.ContextProperties.Add(new PermissionCheckProperty()); } } }
    ?
    3.権限チェックに使用する2つのクラスを定義します:AzMan、AzHelper
    この2つのクラスの機能は、XMLプロファイルからRoleとTaskのマッピング関係を読み込み、RoleにTaskの参照が含まれているかどうかを決定し、現在のRoleがTaskに対する権限を持っているかどうかを決定することです.
    注意:ここでは、プロジェクトの実際の状況に応じて、RoleとTaskのマッピング関係がWindowsのAuthorizatiom Managerまたはデータベースに格納されている場合は、以下のクラスを独自の方法で置き換えることができます.
    この例では、私のロールとTaskの関係はXMLファイルに格納され、XMLファイルのフォーマットは次のようになります.
    
    
    
       
         
    <? xml version="1.0" encoding="utf-8" ?> < ACL > < Tasks > < Task Name ="AddItem" Description =" " /> < Task Name ="ModifyItem" Description =" " /> < Task Name ="RemoveItem" Description =" " /> < Task Name ="ListItem" Description =" " /> </ Tasks > < Roles > < Role Name ="Manager" > < Task Name ="AddItem" /> < Task Name ="ModifyItem" /> < Task Name ="RemoveItem" /> < Task Name ="ListItem" /> </ Role > </ Roles > </ ACL >
    
    
    
       
         

    AzMan.cs /

    
    
    
              
                
    using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace BusinessLogic.Security { public class AzMan { public static bool AccessCheck(string taskName, string[] roles, XmlDocument aclDoc) { XmlNode rootNode = aclDoc.DocumentElement; XmlNodeList roleNodes,taskNodes; bool IsPermissiable = false; for (int i = 0; i < roles.Length; i++) { roleNodes = rootNode.SelectNodes("Roles/Role[@Name='" + roles[i] + "']"); if (roleNodes != null) { taskNodes = roleNodes.Item(0).SelectNodes("Task[@Name='" + taskName + "']"); if (taskNodes.Count != 0) { IsPermissiable = true; break; } } } return IsPermissiable; } } }
    AzHelper.csアシスタントクラス、 のクラスに し、AzManクラスをよりよく び す 、およびパフォーマンスの に づいて、Role<-->TaskのXMLプロファイルをキャッシュする :
    
    
    
              
                
    using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Web; using System.Web.Security; using System.Diagnostics; using System.Reflection; using System.Web.Caching; namespace BusinessLogic.Security { public class AzHelper { /// /// , , ////// public static void PermissionCheck(string taskName) { if (HttpContext.Current != null) { XmlDocument aclDoc = (XmlDocument)HttpContext.Current.Cache["ACLDoc"]; if (aclDoc == null) { CacheXml(); aclDoc = (XmlDocument)HttpContext.Current.Cache["ACLDoc"]; } string[] roles = Roles.GetRolesForUser(); if (!AzMan.AccessCheck(taskName, roles, aclDoc)) throw new UnauthorizedAccessException(" , !"); } } /// /// /// /// /// True/False public static bool IsPermissible(string taskName) { if (HttpContext.Current != null) { XmlDocument aclDoc = (XmlDocument)HttpContext.Current.Cache["ACLDoc"]; if (aclDoc == null) { CacheXml(); aclDoc = (XmlDocument)HttpContext.Current.Cache["ACLDoc"]; } string[] roles = Roles.GetRolesForUser(); aclDoc.Load(HttpContext.Current.Server.MapPath("~/App_Data/ACL.xml")); return AzMan.AccessCheck(taskName, roles, aclDoc); } else return true; } /// /// XML /// private static void CacheXml() { string fileName = HttpContext.Current.Server.MapPath("~/App_Data/ACL.xml"); XmlDocument aclDoc = new XmlDocument(); aclDoc.Load(fileName); HttpContext.Current.Cache.Insert("ACLDoc", aclDoc, new CacheDependency(fileName)); } } }
    .ビジネスロジッククラスの は、 くの がAOPで されているため、ビジネスロジッククラスの は で、 に のステップに けられます.
  • クラスの AOP の チェックを するAttribute:[permissionCheck()]
  • クラスをContextBoundObjectオブジェクト
  • から する
  • メソッド でTask Attributeを して するアクションを する( : のメソッドは じTaskとして できる)
  • .
    :ItemManager.cs
    
    
    
              
                
    namespace BusinessLogic { [PermissionCheck()] public class ItemManager : ContextBoundObject { [Task("AddItem"," ")] public void AddItem(Item item) { //... } } }
    これでいいです.CLRは にクラスのPermissionCheckをチェックしますか?Attributeは、 にメソッド のTaskを し、 のユーザに するRoleを り してマッチングチェックを い、それが できない はUnauthorizedAccessExceptionの を げ し、 で すればよい( えばASP.NETにErrorPageを するなど).その の の Q:もし がプログラムを く 、 ロジッククラスで のTaskを したら、 に したら?A: によってプログラムセットに されたすべてのTaskを り します.コードは の りです.
    
    
    
              
                
    List < string > dic = new List < string > (); StringBuilder sXml = new StringBuilder( " " ); string curDir = this .GetCurrentPath(); Assembly ass = Assembly.LoadFile(curDir + " \\AppFramework.BusinessLogic.dll " ); foreach (Type t in ass.GetTypes()) { MethodInfo[] mis = t.GetMethods(); foreach (MethodInfo mi in mis) { object[] attrs = mi.GetCustomAttributes(false); if (attrs.Length > 0) { foreach (object attr in attrs) { if (attr.GetType().ToString().IndexOf("Task") >= 0) { Task ta = (Task)attr; // Task if (dic.IndexOf(ta.Name) < 0) { dic.Add(ta.Name); sXml.Append(string.Format("\r
    ", ta.Name, ta.Description)); }
    }
    }
    }
    }
    // Task sXml.Append("\r
    "); }
    このコードはTask をXMLファイルに します.SQL Server/Authorzatiom Managerに したい は、コードを し すればいいです.Q:プログラムのロールはどのように しますか?A:ASPならNETアプリは、その のMemberShip Roleメカニズムを することができますか、それとも なQ:もし がインタフェースで にいくつかの を したいならば、あるユーザーがある を うことができないならば、 それに するButtonを したり したり(Disable/Invisible)しますか?A:これはASPを できます.NET 2.0の では、 のユーザーの がTaskを できるかどうかを チェックし、できない は、 されたBool を してButtonなどのコントロールの を し、 のようにします:1)App_Codeの で クラスを します.cs
    
    
    
              
                
    [ExpressionEditor( typeof (PermissionCheckExpressionBuilderEditor))] [ExpressionPrefix( " PermissionCheck " )] public class PermissionCheckExpressionBuilder : ExpressionBuilder { public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) { string taskName = entry.Expression; return new CodePrimitiveExpression(AzHelper.IsPermissible(taskName)); } } public class PermissionCheckExpressionBuilderEditor : System.Web.UI.Design.ExpressionEditor { public override object EvaluateExpression(string expression, object parseTimeData, Type propertyType, IServiceProvider serviceProvider) { //return expression + ":" + parseTimeData + ":" + propertyType + ":" + serviceProvider; string taskName = expression; return AzHelper.IsPermissible(taskName); } }
    )Web.Configに の を えることで、
    
    
    
              
                
    < configuration xmlns ="http://schemas.microsoft.com/.NetConfiguration/v2.0" > < expressionBuilders > < add expressionPrefix ="PermissionCheck" type ="PermissionCheckExpressionBuilder" /> expressionBuilders> configuration>

    3) , :


    • 
      
          
                      
                        
      < asp:Button ID ="Button1" runat ="server" Text ="AddItem" Visible =" " />
    • をページ で することができる.
    • この が であれば である、そうでなければ
      
      
          
                      
                        
      < asp:Button ID ="Button2" runat ="server" Text ="AddItem" Enabled =" " />
    • を する.
      4)コードの で で をチェックしたい は、
      
      
      
                    
                      
      protected void Button1_Click( object sender, EventArgs e) { AzHelper.PermissionCheck("AddItem"); //.. }
      )User<-->Roleのマッピングをどのように するか、Role<-->Taskのマッピングの は で、ASP.NET 2.0にはすでにこの があり、もちろんAPIを して の インタフェースを することもできます.Role-Taskのマッピングでは,まず のコードを いてプログラムセットからすべてのTaskを り し,XMLファイルに し, に にRoleとTaskを してマッピングを う. の に すように、ロールとタスクのマッピングユーザーとロールのマッピング
      ( http://www.850816.com/trackback.asp?tbID=44 )