關于數據權限的控制,可能我們在做很多大型一點的系統都會碰到過,可能每個人設計和解決問題的思路都有所不同,本文介紹我自己框架里面的解決思路。從上一篇《如何在應用系統中實現數據權限的控制功能》里面我們可能對權限控制和數據權限的控制有了一個初步的了解,本文接著進一步介紹在應用系統中,如何集成數據權限的控制功能。
1、數據權限實現思路分析
為了實現數據權限的控制,我們需要在通用的權限系統里面保存好對應角色具有哪些組織機構的數據權限,然后在應用系統中調用API進行過濾數據處理即可。
為了實現以上的功能需求,我們需要在權限系統里面,角色控制哪里增加一個數據權限的數據存儲。
實際的應用系統,當用戶登陸成功后,我們獲取并記錄好其可以管理的公司或者部門,如果是主管的角色,可能有多個公司的數據可以管理,那么可以在程序的頂部,讓用戶選擇管理那個公司的數據即可,如果切換公司,那么刷新現有的界面數據顯示就可以了。
在用戶成功登陸后,我們可以記錄用戶的相關權限控制信息,如他所能控制數據的公司或者部門,把它記錄下來。
Portal.gc.CompanyList = BLLFactory<RoleData>.Instance.GetBelongCompanysByUser(info.ID);
List<int> deptList = BLLFactory<RoleData>.Instance.GetBelongDeptsByUser(info.ID);
Portal.gc.DeptList = deptList;
然后存儲用戶默認的公司ID,并根據用戶是否為管理員(超級管理員、公司管理員),然后構造一個通用的過濾條件,放到全局緩存里面,方便各個模塊使用,如下代碼所示。
//設置選定的公司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;
在主界面的時候,我們可以根據用戶所能管理的公司數據,在頂部初始化公司列表,方便切換選擇,以下是初始化的代碼。
//添加受管理的公司機構
//判斷如果用戶管理的公司數據多于一個,那么就顯示選擇單位列表,并綁定公司數據
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"]了。
我們來看看代碼的實現,其主要的邏輯就是獲取用戶選擇的公司ID,然后根據公司、部門信息,重新構建一個全局的過濾條件,并重新緩存到對應的鍵值里面去,供后面的窗體實現數據的過濾更新。
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;
如果需要對已有的窗體實現數據更新,那么遍歷窗體,并統一實現數據刷新即可。
//遍歷全部窗口,更新
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);
2、窗體數據過濾的實現
從上面的步驟代碼,我們可以看到如何構建一個全局的過濾條件,但是我們獲取數據的時候,如何才能實現數據權限的控制,讓用戶所能看到的數據在可控的范圍內呢?
我們知道,一般窗體數據列表的綁定操作類似如下代碼所示
/// <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();
}
以上就是我對數據權限控制的一些心得和實現思路,希望大家能夠體會其中的思路,并批判性的提出意見和建議。