關於數據權限的控制,可能咱們在作不少大型一點的系統都會碰到過,可能每一個人設計和解決問題的思路都有所不一樣,本文介紹我本身框架裏面的解決思路。從上一篇《如何在應用系統中實現數據權限的控制功能》裏面咱們可能對權限控制和數據權限的控制有了一個初步的瞭解,本文接着進一步介紹在應用系統中,如何集成數據權限的控制功能。html
爲了實現數據權限的控制,咱們須要在通用的權限系統裏面保存好對應角色具備哪些組織機構的數據權限,而後在應用系統中調用API進行過濾數據處理便可。緩存
爲了實現以上的功能需求,咱們須要在權限系統裏面,角色控制哪裏增長一個數據權限的數據存儲。框架
實際的應用系統,當用戶登錄成功後,咱們獲取並記錄好其能夠管理的公司或者部門,若是是主管的角色,可能有多個公司的數據能夠管理,那麼能夠在程序的頂部,讓用戶選擇管理那個公司的數據便可,若是切換公司,那麼刷新現有的界面數據顯示就能夠了。ide
在用戶成功登錄後,咱們能夠記錄用戶的相關權限控制信息,如他所能控制數據的公司或者部門,把它記錄下來。函數
Portal.gc.CompanyList = BLLFactory<RoleData>.Instance.GetBelongCompanysByUser(info.ID); List<int> deptList = BLLFactory<RoleData>.Instance.GetBelongDeptsByUser(info.ID); Portal.gc.DeptList = deptList;
而後存儲用戶默認的公司ID,並根據用戶是否爲管理員(超級管理員、公司管理員),而後構造一個通用的過濾條件,放到全局緩存裏面,方便各個模塊使用,以下代碼所示。post
//設置選定的公司ID(默認爲用戶所在公司的ID) Cache.Instance["SelectedCompanyID"] = info.Company_ID; //設置過濾條件給界面基類使用 string filterCondition = string.Format(" Company_ID = '{0}' ", info.Company_ID); if (!Portal.gc.IsAdmin) { if (deptList.Count > 0) { filterCondition += string.Format(" AND Dept_ID IN ({0})", string.Join(",", deptList)); } else { filterCondition += string.Format(" AND Creator = '{0}' ", info.ID); } } Cache.Instance["DataFilterCondition"] = filterCondition;
在主界面的時候,咱們能夠根據用戶所能管理的公司數據,在頂部初始化公司列表,方便切換選擇,如下是初始化的代碼。ui
//添加受管理的公司機構 //判斷若是用戶管理的公司數據多於一個,那麼就顯示選擇單位列表,並綁定公司數據 if (Portal.gc.CompanyList.Count > 1) { this.repositoryCompanyItem.Items.Clear(); foreach (int company in Portal.gc.CompanyList) { OUInfo companyInfo = BLLFactory<OU>.Instance.FindByID(company); if (companyInfo != null) { this.repositoryCompanyItem.Items.Add(new CListItem(companyInfo.Name, companyInfo.ID.ToString())); } } //多於一個顯示公司下拉列表 this.barCompanyItem.Visibility = DevExpress.XtraBars.BarItemVisibility.Always; } else { //只有一個公司時候,屏蔽公司選擇列表 this.barCompanyItem.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; }
若是多於一個公司,那麼正常的需求是能夠切換公司來查看其它公司的數據的,要實現這個功能,那麼就須要修改登錄的那個全局的過濾條件:Cache.Instance["DataFilterCondition"]了。this
咱們來看看代碼的實現,其主要的邏輯就是獲取用戶選擇的公司ID,而後根據公司、部門信息,從新構建一個全局的過濾條件,並從新緩存到對應的鍵值裏面去,供後面的窗體實現數據的過濾更新。url
CListItem item = this.barCompanyItem.EditValue as CListItem; if (item != null) { //設置選定的公司ID Cache.Instance["SelectedCompanyID"] = item.Value; SetSelectedCompanyName(); //設置過濾條件給界面基類使用 string filterCondition = string.Format(" Company_ID = '{0}' ", item.Value); if (!Portal.gc.IsAdmin) { if (Portal.gc.DeptList.Count > 0) { filterCondition += string.Format(" AND Dept_ID IN ({0})", string.Join(",", Portal.gc.DeptList)); } else { filterCondition += string.Format(" AND Creator = '{0}' ", Portal.gc.UserInfo.ID); } } Cache.Instance["DataFilterCondition"] = filterCondition;
若是須要對已有的窗體實現數據更新,那麼遍歷窗體,並統一實現數據刷新便可。spa
//遍歷所有窗口,更新 foreach (WHC.Framework.BaseUI.BaseDock form in this.MdiChildren) { form.SelectedCompanyID = item.Value; form.DataFilterCondition = filterCondition; form.FormOnLoad(); } string message = string.Format("您已經切換數據顯示:{0}", item.Text); MessageDxUtil.ShowTips(message);
從上面的步驟代碼,咱們能夠看到如何構建一個全局的過濾條件,可是咱們獲取數據的時候,如何才能實現數據權限的控制,讓用戶所能看到的數據在可控的範圍內呢?
咱們知道,通常窗體數據列表的綁定操做相似以下代碼所示
/// <summary> /// 綁定列表數據 /// </summary> private void BindData() { //entity this.winGridViewPager1.DisplayColumns = displayColumns; this.winGridViewPager1.ColumnNameAlias = CallerFactory<ICustomerService>.Instance.GetColumnNameAlias();//字段列顯示名稱轉義 string where = GetConditionSql(); PagerInfo pagerInfo = this.winGridViewPager1.PagerInfo; List<CustomerInfo> list = CallerFactory<ICustomerService>.Instance.FindWithPager(where, ref pagerInfo); this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<CustomerInfo>(list); this.winGridViewPager1.PrintTitle = "客戶信息列表"; }
因此主要的數據控制,就在函數GetConditionSql()裏面了,那麼這個裏面,咱們如何整合前面的過濾條件呢?
下面是一個案例代碼。
/// <summary> /// 根據查詢條件構造查詢語句 /// </summary> private string GetConditionSql() { //若是存在高級查詢對象信息,則使用高級查詢條件,不然使用主表條件查詢 SearchCondition condition = advanceCondition; if (condition == null) { condition = new SearchCondition(); if(customGridLookUpEdit1.EditValue != null) { condition.AddCondition("ID", customGridLookUpEdit1.EditValue.ToString(), SqlOperator.Equal); } condition.AddCondition("Deleted", 0, SqlOperator.Equal);//不顯示刪除的 } string where = condition.BuildConditionSql().Replace("Where", ""); //若是是單擊節點獲得的條件,則使用樹列表的,不然使用查詢條件的 if (!string.IsNullOrEmpty(treeConditionSql)) { where = treeConditionSql + " AND Deleted = 0 ";//不顯示刪除的 } //數據權限的過濾:過濾規則,若是指定公司,以公司過濾,若是進一步指定部門,以公司+部門進行過濾;不然以我的的數據展現 //若是過濾條件不爲空,那麼須要進行過濾 if (!string.IsNullOrEmpty(this.DataFilterCondition)) { where += string.Format(" AND {0}", this.DataFilterCondition); } return where; }
咱們主要關注下上面紅色部分便可,由於咱們已經加上了標準的過濾條件了,這樣咱們就能夠看到本身管理的數據了。
爲了實現統一的數據控制,咱們要求整個業務表的設計,須要引入下面幾個標準的字段,這樣就能很好使用過濾條件進行數據的過濾了。
前面也介紹到了,窗體能夠統一刷新,其奧祕就是它們遵循統一的一個數據加載接口,咱們初始化窗體數據的函數代碼以下所示。
/// <summary> /// 編寫初始化窗體的實現,能夠用於刷新 /// </summary> public override void FormOnLoad() { InitDictItem(); BindData(); InitCustomerPage(); }
因此它們就可以統一調用FormOnLoad來統一刷新數據,就是這個道理。
//遍歷所有窗口,更新 foreach (WHC.Framework.BaseUI.BaseDock form in this.MdiChildren) { form.SelectedCompanyID = item.Value; form.DataFilterCondition = filterCondition; form.FormOnLoad(); }
以上就是我對數據權限控制的一些心得和實現思路,但願你們可以體會其中的思路,並批判性的提出意見和建議。