关于数据权限的控制,可能咱们在作不少大型一点的系统都会碰到过,可能每一个人设计和解决问题的思路都有所不一样,本文介绍我本身框架里面的解决思路。从上一篇《如何在应用系统中实现数据权限的控制功能》里面咱们可能对权限控制和数据权限的控制有了一个初步的了解,本文接着进一步介绍在应用系统中,如何集成数据权限的控制功能。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(); }
以上就是我对数据权限控制的一些心得和实现思路,但愿你们可以体会其中的思路,并批判性的提出意见和建议。