Saturday, 31 January 2009

Field level security performance with Rhino Security

Last year I wrote a post on how to add field level security in your ASP.NET MVC application. When testing the solution it turned out that the performance was unacceptable. The reason for this is that we need to check the permissions for every control on a create or edit page. For some of our entities we have rather big edit pages with more than 20 controls. So we needed to come up with another solution. I sat together with a colleague and together we came up with the following.

Since most of the time an edit or a create page contains properties of a single entity and maybe some related entities we thought it would be better to get the permissions of all fields of an entity in one go and store them somewhere for the lifetime of a request.

That's why we now have a "SecurityService" that keeps a dictionary of "AccessRights" like this:

   1: public class SecurityService : ISecurityService
   2:     {
   3:         private readonly Dictionary<Type, ICollection<Permission>> accesrights =
   4:             new Dictionary<Type, ICollection<Permission>>();

When getting the rights we first check whether we do not already have them and otherwise we go and get them:

   1: private ICollection<Permission> GetFieldLevelPermissionsFor(Type t)
   2: {
   3:     User user = userService.GetUser(HttpContext.Current.User.Identity.Name);
   4:     DetachedCriteria criteria = DetachedCriteria.For<Permission>();
   5:     criteria.Add(Restrictions.Eq("UsersGroup", user.UserGroup));
   6:     DetachedCriteria subcriteria = criteria.CreateCriteria("Operation", "Operation", JoinType.InnerJoin);
   7:     subcriteria.Add(Restrictions.Eq("OperationType", OperationType.Field));
   8:     subcriteria.Add(Restrictions.Like("Name", string.Format("/{0}/", t.Name), MatchMode.Start));
   9:     return Repository<Permission>.FindAll(criteria);
  10: }
  11:  
  12: public ICollection<Permission> GetRightsForType<T>()
  13: {
  14:     return GetRightsForType(typeof (T));
  15: }
  16:  
  17: public ICollection<Permission> GetRightsForType(Type t)
  18: {
  19:     ICollection<Permission> rights = null;
  20:  
  21:     if (accesrights.Keys.Contains(t))
  22:     {
  23:         rights = accesrights[t];
  24:     }
  25:     else
  26:     {
  27:         //rechten ophalen en in dictionary steken
  28:         rights = GetFieldLevelPermissionsFor(t);
  29:         accesrights[t] = rights;
  30:     }
  31:  
  32:     return rights;
  33: }

The secured textbox extension method has been changed. It now uses the "SecurityService".

   1: public static string SecuredTextBox<T>(this HtmlHelper htmlHelper, string name, string labelText, 
   2:             Expression<Func<T,object>> property, object instance, IDictionary<string, object> htmlAttributes, string additionalHtml)
   3:         {
   4:             var securityService = SystemFactory.BuildUp<ISecurityService>();
   5:             var level = securityService.GetAccessLevel(property);
   6:  
   7:             if (level == AccessLevel.None)
   8:             {
   9:                 return String.Empty;
  10:             }
  11:  
  12:             htmlAttributes = htmlAttributes ?? new Dictionary<string, object>();
  13:             htmlAttributes.Add("id", name);
  14:  
  15:             // set the value if an instance was passed
  16:             if (instance != null)
  17:             {
  18:                 var compiled = property.Compile();
  19:                 var value = compiled((T)instance);
  20:  
  21:                 if (value != null)
  22:                     htmlAttributes.Add("value", value);
  23:             }
  24:  
  25:             // readonly? -> add readonly attribute
  26:             if (level == AccessLevel.Read)
  27:                 htmlAttributes.Add("readonly", "readonly");
  28:  
  29:             string dateformat = string.Empty;
  30:             string addHtml = additionalHtml;
  31:             if (htmlAttributes.Contains(new KeyValuePair<string, object>("class", "date")))
  32:             {
  33:                 dateformat = additionalHtml;
  34:                 addHtml = string.Empty;
  35:             }
  36:             return string.Format("<div style=\"padding: 0.5em\"><label for=\"{0}\">{1}:{2}  {3}</label><div>{4} {5}</div></div>", name, htmlHelper.Encode(labelText),
  37:                                     (htmlAttributes.ContainsKey("mandatory") ? "<span class='reqMark'>*</span>" : string.Empty),
  38:                                     dateformat,
  39:                                     htmlHelper.TextBox(name, htmlAttributes), addHtml);
  40:         }        

It is however a local variable, so you must be wondering how it is possible that the securityservice still keeps state between calls to SecuredTextBox within the same request. There we have Windsor to help us. There is a "PerWebRequest" lifestyle that you can use so that your components are only created once per http request. So we just configured our "SecurityService" in Binsor as follows and we're done.

   1: Component("Security_Service",
   2:            ISecurityService,
   3:            SecurityService,LifestyleType.PerWebRequest)    

4 comments:

123 said...

喜餅禮盒 喜餅價格 訂婚禮盒 訂婚喜餅
素食月子餐 飛梭雷射 柔膚雷射 獸醫師 創業鞋之澡堂 洗鞋子 洗包包加盟彌月禮盒 彌月禮 玻尿酸 皮膚科 皮膚科診所 肉毒桿菌 肉毒桿菌瘦臉 脈衝光 除斑 Flex PCB PCB Electronic PCB 衝孔網 菱型網 不鏽鋼 壯陽 成人用品春藥 壯陽藥品 持久 手工水餃 中華湯包 mini usb 催情 增大 模具廠 104法拍網 信義房屋 房屋買賣 台北法拍屋 塑膠射出成型 模具 Odm 塑膠射出模具 Oem代工廠 塑膠射出 塑膠射出廠 模具設計 Precision Mold加盟創業 冷凍宅配 宅配美食 Light guide panels Plastic Products Mold design 沖孔網

123 said...

馬桶不通 food forming patty machine boiling machine 化妝品包 裝 紙盒 breading machine vegetable machine日立冷氣 Plastic Drinking Cups宜蘭民宿 宜蘭旅遊教育訓練 品質管理 Ohsas 18001casino gaming machine 泰國清邁 iso認證 iso團體旅遊簽證 slot game machine slot machine cabinet 便宜機票展場設計 二手車 中古車 Bmw 中古車買賣 汽車借款gaming machine manufacturer gaming machine 大陸直航新竹餐廳下午茶特色餐廳景觀餐廳親子餐廳

123 said...

彌月禮盒團購美食 印刷 彩色印刷 包裝 設計pe膜 冬令營 food processing equipment frying machine Telecom PCB 泡菜 團購美食油飯麻糬
創業加盟 水餃 壯陽食品 早洩 情趣用品 湯包 DC Jack tact switch Slide switch Phone Jack USB connector RCA Jack開 關 製網 菱形網 不鏽鋼網 金屬網 無塵室射出 Disposable plastic cups Disposable plastic cups Disposable products 宜蘭住宿 ECO products Biodegradable plastic PLA 律師事務所 律師 寵物醫院polylactic acid Biodegradable

123 said...

搬家公司 月子中心 seo 關鍵字廣告 關鍵字 google關鍵字廣告 關鍵字行銷 網路行銷 通姦 徵信社 外遇 桃園房屋仲介 桃園房屋買賣 桃園房屋 醫學美容診所 淨膚雷射 雷射溶脂 飛梭雷射 微晶瓷 植髮 團體服 團體服訂做 醫學美容診所 肉毒桿菌 肉毒桿菌瘦臉 醫學美容 整型診所 美國月子中心 徵信 徵信公司 出軌 清潔公司台北搬家公司 整形 韓風整形 整形 韓風整形 老人癡呆症 情緒管理 訂房網 線上訂房