对DbRuleAuthorizationProvider的修改
????有用過Security Application Block(以下簡稱SAB)的朋友都知道,它的權限規則是直接存在配置文件中,并沒有提供存在數據庫的實現形式,大家也都知道已經有人對它進行了擴展,提供了一個叫DBRulesAuthorizationProvider的Provider。(http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=c0b0ce8e-1b72-44ab-b300-f369eb18664a)。對于我來說,這是一個非常不錯的Provider,現在都它了。可是卻存在一個問題,每次驗證授權的時候都去讀取數據庫,特別是當我想得到某個或某個角色所具有的所有權限時(SAB使用的是邏輯表達式的形式進行授權,除了在程序中去遍歷所有的權限規則,我目前是沒有想到有其它別的好的辦法可以獲得某個人所具有的所有功能,如果有人有好的辦法請告知。),去遍歷權限表一個一個地去驗證這個用戶(或角色)是否具有這個權限,而不得不去循環訪問數據庫。比如有100個權限,我就要訪問100次數據庫,我想這對每個人來說都是不可接受的,也是我對這個Provider進行修改的主要原因。修改的目的就是要給它加上緩存權限的功能,要把數據庫中規則表的所有記錄都讀取下來,緩存在本地。這樣以后進行授權驗證的時候就不用擔心頻繁訪問數據庫了。緩存?緩存在內存中合適嗎?Enterprise Library 也有提供緩存程序塊(Caching Application Block ),可以提供多種不同的緩存方式,可以緩存在內存,文件和本地數據庫中。經過衡量,決定緩存在文件中。OK,打開DBRuleAuthorizationProvider源碼......
??? 找到DBRulesAuthorizationProviderData.cs,我不知道它叫什么名字,反正在這一整個企業庫里面每一個的配置節都有這樣的一個叫ProviderData的類。在里面添加上一個屬性的一個構造函數。
//使用的緩存管理器的名稱
[XmlAttribute(AttributeName?=?"cacheManager")]
????????public?string?CacheManager
????????{
????????????get?{return?this.cacheManager;}
????????????set?{this.cacheManager????=?value;}
????????}
public?DbRulesAuthorizationProviderData(string?name,string?database,string?cacheManager)?:?this(name,database)
????????{
????????????this.cacheManager????=?cacheManager;
????????}
??? 修改DBRulesAuthorizationProviderNode.cs,修改這個是為了讓我們使用Configuration Console的時候可以為它指定一個緩存管理器。如下圖
在里面添加如下代碼 private?CacheManagerNode?cacheManager;
????????private?ConfigurationNodeChangedEventHandler?onCacheManagerRemoved;
????????private?ConfigurationNodeChangedEventHandler?onCacheManagerRenamed;
[Editor(typeof(ReferenceEditor),?typeof(UITypeEditor))]
????????[ReferenceType(typeof(CacheManagerNode))]
????????[Required]
????????[Description("The?database?instance?that?will?be?used?to?query?for?rules")]
????????public?CacheManagerNode?CacheManager
????????{
????????????get?{?return?this.cacheManager;?}
????????????set
????????????{
????????????????ILinkNodeService?service?=?GetService(typeof(ILinkNodeService))?as?ILinkNodeService;
????????????????Debug.Assert(service?!=?null,?"Could?not?get?the?ILinkNodeService");
????????????????this.cacheManager?=?(CacheManagerNode)service.CreateReference(cacheManager,?value,?onCacheManagerRemoved,?onCacheManagerRenamed);
????????????????this.DbRulesAuthorizationProviderData.CacheManager?=?string.Empty;
????????????????if?(this.cacheManager?!=?null)
????????????????{
????????????????????this.DbRulesAuthorizationProviderData.CacheManager?=?this.cacheManager.Name;
????????????????}
????????????}
????????}
private?void?OnCacheManagerRemoved(object?sender,ConfigurationNodeChangedEventArgs?args)
????????{
????????????this.cacheManager????=?null;
????????}
????????private?void?OnCacheManagerRenamed(object?sender,ConfigurationNodeChangedEventArgs?args)
????????{
????????????this.DbRulesAuthorizationProviderData.CacheManager????=?args.Node.Name;
????????}
//?
????????//??extended?by?hjf
????????//?
????????private?void?CreateCachingSettingsNode()
????????{
????????????if(!CachingSettingNodeExistes())
????????????{
????????????????AddConfigurationSectionCommand?cmd????=?new?AddConfigurationSectionCommand(Site,typeof(CacheManagerSettingsNode),CacheManagerSettings.SectionName);
????????????????cmd.Execute(Hierarchy.RootNode);
????????????}
????????}
????????private?bool?CachingSettingNodeExistes()
????????{
????????????CacheManagerSettingsNode????node????=?Hierarchy.FindNodeByType(typeof(CacheManagerSettingsNode))?as?CacheManagerSettingsNode;
????????????return?(node?!=?null);
????????}
修改構造函數加上
this.onCacheManagerRemoved????=?new?ConfigurationNodeChangedEventHandler(this.onCacheManagerRemoved);
????????????this.onCacheManagerRenamed????=?new?ConfigurationNodeChangedEventHandler(this.onCacheManagerRenamed); 修改ResolveNodeReferences函數加上
CacheManagerSettingsNode?cacheManagerSettingNode????=?Hierarchy.FindNodeByType(typeof(CacheManagerSettingsNode))?as?CacheManagerSettingsNode;
????????????Debug.Assert(cacheManagerSettingNode?!=?null,"How?is?it?that?the?cachemanager?settings?are?not?there?");
????????????CacheManagerCollectionNode?cacheManagerCollectionNode????=?Hierarchy.FindNodeByType(typeof(CacheManagerCollectionNode))?as?CacheManagerCollectionNode;
????????????this.cacheManager????=?Hierarchy.FindNodeByName(cacheManager,this.DbRulesAuthorizationProviderData.CacheManager)?as?CacheManagerNode; 修改AddDefaultChildNodes()函數,加上
CreateCachingSettingsNode(); OK,就這樣,把編譯好的DLL拷到C:\Program Files\Microsoft Enterprise Library\bin,再添加 Database Authorization Provider,配置項,就加了一個CacheManager的值項了.
??? 現在我們看看DbRulesManager.cs,讀數據庫數據的操作都在這里了,現在CacheManager就用在這邊了。用了緩存后,我是將數據庫中所有的規則權限都一次性讀到本地中,用CacheManager緩存起來。原來還以為自己要寫存儲過程,仔細看一下代碼,它已經寫好了一個方法,public AuthorizationRuleDataCollection GetAllRulesAsCollection(){},讀出所有的Rule,存在AuthorizationRuleDataCollection 里。查看一下AuthorizationRuleDataCollection 的定義。太好了,它可以根據RuleName ,取出對應的RuleData。那我只要把生成的AuthorizationRuleDataCollection 對象保存起來不就可以了,還有一個問題AuthorizationRuleData是不可序列化的,沒法緩存。改一下Security 的源碼就行了,給AuthorizationRuleData加上[Serializable]屬性。新增代碼 private?const?string?STR_CACHE_RULESCOLLECTION????=?"Cache:RulesCollection";//緩存KEY
private?Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager?cacheManager????=?null;
//增加構造函數,初始化cacheManager
public?DbRulesManager(string?databaseService,string?cacheManagerService,ConfigurationContext?config)?:?this(databaseService,config)
????????{
????????????CacheManagerFactory?factory????=?new?CacheManagerFactory(config);
????????????cacheManager????=?factory.GetCacheManager(cacheManagerService);
????????}
//增加Property,外面調用這個屬性就可以了
public?AuthorizationRuleDataCollection?AllRuleCollection
????????{
????????????get
????????????{
????????????????AuthorizationRuleDataCollection?m_rulesCollection????=?null;
????????????????if(cacheManager[STR_CACHE_RULESCOLLECTION]?!=?null)
????????????????????m_rulesCollection????=?cacheManager[STR_CACHE_RULESCOLLECTION]?as?AuthorizationRuleDataCollection;
????????????????if(m_rulesCollection?==?null)
????????????????{
????????????????????m_rulesCollection????=?GetAllRulesAsCollection();
????????????????????AllRuleCollection????=?m_rulesCollection;
????????????????}
????????????????return?m_rulesCollection;
????????????}
????????????set
????????????{
????????????????if(value?==?null)
????????????????????cacheManager.Remove(STR_CACHE_RULESCOLLECTION);
????????????????else
????????????????????//
????????????????????//?緩存數據一天。
????????????????????//
????????????????????cacheManager.Add(STR_CACHE_RULESCOLLECTION,value,CacheItemPriority.High,null,new?SlidingTime(new?TimeSpan(1,0,0,0)));
????????????}
????????}
最后,我們來修改DBRulesAuthorizationProvider.cs,這個就是這個Provider對外提供的調用方法,我們只要修改根據RuleName讀出Expression的那段代碼就行了.
//增加字段
private?string?cacheManager;
//????????????????mgr?=?new?DbRulesManager(database,?this.securityConfigurationView.ConfigurationContext);
//用這個函數替換上面的函數
????????????mgr?=?new?DbRulesManager(database,cacheManager,this.securityConfigurationView.ConfigurationContext);
//增加下面的函數
private?BooleanExpression?GetParsedExpression(string?Expression)
????????{
????????????Parser?p????=?new?Parser();
????????????return?p.Parse(Expression);
????????}
//修改IConfigurationProvider的public?override?void?Initialize(ConfigurationView?configurationView)增加這句代碼
cacheManager????=?data.CacheManager;
整個的修改工作就這樣了,把編譯好的DLL Copy到Enterprise Library安裝目錄的bin目錄下,就可以使用了,有一點要注意,這期間我修改了Security 工程的AuthorizationRuleData類,請也將它重新編譯一下,Copy 到bin 目錄下,否則數據將無法緩存。還有一點就是如何控制緩存的過期,在修改權限表達式的時候可要記住清空緩存喔,我曾想在DbRulesAuthorizationProvider,增加一個方法設計緩存的過期,可是程序是通過IAuthorizationProvider接口來調用的,修改它就要修改很多地方了。而為了使用的一致性又不想運行時去將它轉換成DbRulesAuthorizationProvider類型.....還在考慮中,呵呵
??? 第一次隨筆,組織得會比較亂,沒辦法,就這水平了,請見諒。
轉載于:https://www.cnblogs.com/hjf1223/archive/2005/08/11/212622.html
總結
以上是生活随笔為你收集整理的对DbRuleAuthorizationProvider的修改的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 找到一个不错的ASP.net电子图书下载
- 下一篇: File,FileInfo;Direct