【开源框架】EFW框架中的系统权限与页面子权限详解
EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0
EFW框架实例源代码下载:http://pan.baidu.com/s/1eQCc69G
使用EFW框架开发系统,框架中提供了两个级别的权限控制:角色菜单权限与页面子权限。
角色菜单权限:就是不同的用户登录系统后,根据配置的权限动态生成的菜单,管理员一般全部菜单都可以看到,而一般用户很多菜单就看不到;用户绑定角色,角色配置系统菜单,系统根据登录的用户先查找绑定的角色,再根据角色查找配置的菜单,然后将菜单显示框架中;角色放在用户与菜单之间,主要就是简化用户的配置;如果没有角色,给每个用户配置菜单,那配置得有多麻烦;
页面子权限:一般来说权限达到菜单级别就能满足大部分情况,而有些系统或功能对权限控制要求更细,需要达到页面中功能也要能够加入权限配置;为了满足这种需求,EFW框架提供了页面子权限的功能,当然配置起来比菜单级的肯定要复杂些;先维护好每个页面的子权限清单,再配置好每个角色与页面子权限清单的关系,然后打开页面的时候,根据页面与用户就可以查出配置页面子权限,根据这个配置信息界面需要进行额外编码完成界面上不同权限的操作;
见下图:页面子权限的效果图
给实例中的“书籍管理”界面设置页面子权限,给界面的“新增”、“保存”和“导出”三个功能按钮配置权限控制;
图中上面两个界面,前一个页面子权限三个都没勾,那么后面界面上的三个按钮显示都不可操作;
图中下面两个界面,前一个页面子权限三个都勾上,那么后面界面上的三个按钮就变成可以操作了;
1.如何使用页面子权限
1)在“用户权限管理”界面维护好菜单的页面子权限清单,并给角色配置子权限
见下图,在红框部分输入权限标识和名称,点击保存就可以增加一个页面子权限,选中网格一条记录点击删除就移除页面子权限;一个菜单的页面子权限的标识不能够重复,页面子权限可以随便增加,但肯定要跟实际界面有关系;
维护好页面子权限后,再选择左边网格中的角色,勾选页面子权限完成权限配置;
2)界面控制器获取页面子权限数据,并编写代码控制界面展示
见下图,bookwinController控制器可以直接得到父类BaseController中的GetPageRight属性为页面子权限的数据,用DataTable存储;然后编写代码判断数据中的“new”、“delete”和“export”的值是0或1,用来设置三个按钮的状态;
还有BaseController如何取得页面子权限的数据,是通过框架中的ExecuteFun对象实现的,ExecuteFun是用来调用框架中所有注册到框架中的委托代码;
2.关于“委托代码”的调用
上文中在获取页面子权限数据的时候用到了框架中的“委托代码”,讲解“委托代码”之前先了解一下调用外部程序集代码的三种方式:
1)引用调用,选择项目引用可以右键添加外部程序集后,代码中就可以直接使用引用程序集中定义的公共对象;
2)反射调用,项目不用引用程序集,但要知道程序集的名称、类的名称与方法属性,就可以用反射方式动态调用程序集中的代码;
3)通过框架中的委托代码调用,程序集将代码注册到框架中,那么项目中不用关心是哪个程序集,只要使用框架中的Excutefun对象就可以调用所有注册到框架的代码;
第一种方式是经常用到的,用起来非常方便,但是有些情况下这种方式无法使用,比如两个程序集相互调用的时候,就不能相互引用,因为编译就会报错。那么这时候就会用到“反射”第二种方式,反射就是用起来比较麻烦,需要记住一些名词,而且不能书写错误。当程序集中的调用关系很复杂的话,“反射”这种方式用起来也麻烦,调用入口太多,容易搞错。这时候就需要用到第三种方式“委托代码”,这样调用都是调用框架中的对象,但是代码是通过委托的方式下放到不同的程序集去的;
你可能会觉得,把引用关系设计这么复杂干嘛,全部单向引用,都需要用到的对象就另外新建一个公共类库不就行了。这种想法是好的,一次前期的设计得非常全面才能把公共类库规划得很好,还有就是把一些对象与原有程序集分离到公共类库中,从代码的结构上有点影响代码的阅读,代码的编写也变得复杂不连贯;所以觉得“委托代码”是一种解决这种问题的不错方式;
委托代码注册:
public class BaseLibShareFunCode : ExecuteFun { public override void LoadFun(System.Collections.Hashtable codeList) { string funName; FunCode code; //getPageRight 页面子权限数据获取 //调用方法:DataTable data=(DataTable)ExecuteFun.invoke("getPageRight",1,1); funName = "getPageRight"; code = delegate(object[] para) { int menuId = Convert.ToInt32(para[0]); int userId = Convert.ToInt32(para[1]); DataTable data = null; string strsql = @"SELECT Code,Name, ( CASE WHEN (SELECT COUNT(*) FROM BaseGroupPage a LEFT JOIN BaseGroupUser b ON a.GroupId=b.GroupId WHERE b.UserId={1} AND a.PageId=P.Id)>0 THEN 1 ELSE 0 END ) Val FROM BasePageMenu P WHERE MenuId={0}"; strsql = string.Format(strsql, menuId, userId); data = oleDb.GetDataTable(strsql); return data; }; codeList.Add(funName, code); // } }
委托代码调用:
/// <summary> /// 获取页面子权限 /// </summary> public DataTable GetPageRight { get { DataTable data = (DataTable)ExecuteFun.invoke(oleDb,"getPageRight", MenuId, GetSysLoginRight.UserId); return data; } }
3.页面子权限在不同系统Web、Winform、WCF下的区别
上文实例是讲得Winform系统中的使用,其实三种不同系统原理都一样,只是系统结构的差别所以实现方式有点区别而已;
Winform系统很简单,直接调用BaseController中的GetPageRight属性就能获取页面子权限数据,界面可以直接操作GetPageRight属性返回的DataTable数据,编写权限控制代码;
public class bookwinController : BaseController { IfrmBook frmBook; public override void Init() { frmBook = (IfrmBook)DefaultView; //初始化加载书籍目录 GetBooks(); GetPie(); //获取页面子权限 frmBook.SetPageRight(GetPageRight); } ...
Web系统,可以从AbstractJqueryController中获取GetPageRight属性,但数据是DataTable结构,所以界面还需要通过Ajax向调用后台控制器将DataTable数据转成json数据到界面JS中,再用JS代码编写权限控制代码;
public class bookController : EFWCoreLib.WebFrame.Controller.AbstractJqueryController { [WebMethod] public void GetPageRightData() { int menuId = Convert.ToInt32(ParamsData["menuId"]); DataTable dt = GetPageRight(menuId); TxtJson = ReturnSuccess("", ToJson(dt));//前台用requestAjax请求 } ...
//页面子权限控制代码 function SetPageRight() { var menuId = $.query.get('MenuId'); if (menuId) { requestAjax('Controller.aspx?controller=bookController&method=GetPageRightData', { menuId: menuId }, function (data) { PageRight = data; $.each(PageRight, function (i, n) { if (n.Code == 'new' && n.Val == 0) { $('#btnNew').hide(); } if (n.Code == 'delete' && n.Val == 0) { } if (n.Code == 'export' && n.Val == 0) { } }); }); } }
WCF系统,跟Web系统一样不能从BaseWCFClientController中直接获取,需要使用WCF服务从后台控制器中获取GetPageRight数据,然后转成Json数据传递给界面控制器,再编写权限控制代码;
[WCFController] public class bookWcfController : JsonWCFController { //根据界面传递的菜单ID获取页面子权限数据 [WCFMethod] public string GetPageRightData() { int menuId = ToInt32(ParamJsonData); DataTable dt = GetPageRight(menuId); return ToJson(dt); } ...
public class bookwcfclientController : BaseWCFClientController { IfrmBook frmBook; public override void Init() { frmBook = (IfrmBook)DefaultView; //初始化加载书籍目录 GetBooks(); //获取页面子权限数据 PageRight = ToDataTable(InvokeWCFService("bookWcfController", "GetPageRightData", ToJson(MenuId))); frmBook.SetPageRight(PageRight); } ...
总结:EFW框架中的权限还是能满足大部分的项目开发了,具有菜单级权限与页面级权限,从粗到细;本文主要讲解的是页面子权限的内容,注意页面子权限的两部分操作是完全独立的,定义子权限清单与编写权限控制代码,但是后者又依赖前者,通过标识关联起来;
下一章提前看:《掌握EFW框架的需要抓住以下几个方面》
掌握和使用不同,如果你只要求会使用EFW框架那完全没必要深入学习框架的代码,博文也只学习前面几章就行了,但如果你作为一个开发团队的头,讲EFW框架运用在项目中的话,那你就必须深入掌握EFW框架,虽然没必要把框架中的没一段代码搞清楚,但一定要做到心里有数,能够自主解决项目开发中遇到问题,也知道怎么扩展框架。本章讲得几个方面是为学习框架提供一个可参考的脉络,防止深陷在众多功能中。
1.必备的技术知识
2.框架核心的功能点之间的关联
3.业务比代码更重要
4.阅读代码的方法,了解“代码层次结构”优先“代码具体细节”
5.框架开源分享的意义是一些“编程思路的分享”,而不是又多一个开发工具供选择而已。所以博文更注重把框架中的核心点拿出来讨论,引导大家向更深层次的思考,找到更好的实现方法;要是写成操作手册一样的文章,意义不大;
编程能力等级的提升是多么的不容易,这个过程是没有什么具体的方法或操作步骤,而是那“一刹那”的豁然开朗;“一刹那”之后这一层的东西基本已经融会贯通、了然于胸,都能说出个之所以然来,但要达到这“一刹那”之前的积累是必不可少的,而代码量是一个具体可参考的指标;
就跟刀客成为一流高手之前的挥刀次数;