订餐系统之权限设计

  大约从两年前开始真正的进入园子,各位园友们的文章真让我受益匪浅,从编程思想,各类工具,代码技巧,管理心得...方方面面太多了。也不知从何时开始萌生了自己写文章的念头,但终于还是不敢写,担心自己的技术不太好,写的文章给园子摸黑了。幸好,有我家妞妞一直从旁鼓励:如果有一部分人,哪怕是一小部分人看了,觉得有益,就为园子做贡献了,当然,如果还有人提出更好的意见或建议,那对自己,对更多人就有益了。于是,借着双休,早上7点就迫不及待爬起来开始真正的“园路”了。不知道各位程序员有没有同感:平时早上总是睡不够,一到放假反倒没瞌睡了。

  对于这个标题我想解释下,以免各们觉得我是在做seo,当然也许是我小人之心了。从10年1月22号,开始工作,一直在现在的公司做此系统的开发,程序员嘛,三句话不离老本行,所以用了“订餐系统”作为前缀,我想以后的文章也会是关于这个的方方面面了(下一篇文章应该是订餐系统之按距离[根据经纬度]排序、搜索)。至于权限,其实园子中已经有很多前辈写过很多优秀的东西了,特别是吉日嘎拉,他们都是数年的积累了,才有如此稳定的东西。当然,我们的权限系统也是几年来数十个客户(当然,只对重点客户在用此权限系统 )反馈、升级后的结晶,其中包括台湾某订餐网站及北京某团购旗下订餐网站。也是他们的好评让我有信心再写这个经久不衰的话题。当然,最重要的还是,我觉得此权限系统中每个细节可控和集成轻量(简单,但重复,这也是此文的另一个目的,希望大家指点下),也是自己从设计,到编码一手完成的(还是有点私心哈)。因为第一次写,所以罗嗦了半天,下面开始才真正权限之路了。

  首先还是需求:此权限系统可以控制到一个模块能否查询、添加、编辑、删除等操作,另外也可以根据需求添加导出,导入,分配权限等权限控制,按两级分类,如图(1):

    

                                                                                                     图(1)

       至于数据表的设计和目前大家看到的表差不了多少,如图(2):

                                

                                                                                             图(2)

      管理员表- EAdmin:Rem表示角色编号,Permission表示类型,1表示超级管理员(不受权限控制,提高速度,PS.判断权限是个复杂的过程),0表示普通管理员

      角色表-sys_Roles:目前一个管理员只能对应一个角色;

  模块表-sys_Module:此表数据就是对应系统的系统中每个模块,如用户管理,订单管理,用户管理又分统计管理,积分管理等。 M_ParentID表示父类编号,M_PageCode用于和sys_RolePermission关联,一级分类形如:S00,S01.... 二有分类形如:S00M01,S00M02....,展现形式如图(3):

            

 

                                              图(3)

  模块操作权限表-sys_ModulePermition:此表关联sys_Module,记录sys_Module中每个功能所有操作项目,如:查看,添加,编辑,删除,统计等,展现形式如图(4),pvalue表示每个操作项的权限(2的指数次方),用于后面权限的判断

         

                                              图(4)

  角色-权限关系表-sys_RolePermission:此表保存每个角色对每个模块的相关操作权限,P_Value保存对于某个模块所有操作项对应的权值之禾

  以上便是我们的权限系统涉及的所有表,可能大部分权限的设计应该都差不多吧,差别应该都在控制方式,展现形式上的。除sys_ModulePermition这个设计外,我大部分也是参考的公司购买的一个权限系统,加入我们的元素,客户需求。

  目前这个权限系统要应用于某个项目时,同事总有些怨言,集成简单,但要做很多重复的事,如:把每个功能块加到数据库中,再为其添加操作项,如,查询、添加、编辑、删除等,这个也许大家也可以接受,我想任何权限系统都避免不了的。但是,另一点就是我自己都介绍不了的,就是每个操作前,都要添加类似的判断代码,如下面代码中注释的两行:

显示代码
if (Request["id"] == null)
        {
            //判断添加权限
            int _rs = WebUtility.checkOperator(2);
            if (_rs == 0)
            {
                AlertScript.RegScript(this.Page, this.UpdatePanel1, "alert('无操作权限','success','true',5);init();");
                return;
            }
            if (dal.Add(model) > 0)
            {
                AlertScript.RegScript(this.Page, UpdatePanel1, "tipsWindown('提示信息','text:保存成功!','250','150','true','1000','true','text');");
            }
            else
            {
                AlertScript.RegScript(this.Page, UpdatePanel1, "tipsWindown('提示信息','text:保存失败!','250','150','true','1000','true','text');");
            }
        }
        else
        {
            //判断编辑权限权限
            int _rs = WebUtility.checkOperator(3);
            if (_rs == 0)
            {
                AlertScript.RegScript(this.Page, this.UpdatePanel1, "alert('无操作权限','success','true',5);init();");
                return;
            }
            if (dal.Update(model) > 0)
            {
                AlertScript.RegScript(this.Page, UpdatePanel1, "tipsWindown('提示信息','text:保存成功!','250','150','true','1000','true','text');");
            }
            else
            {
                AlertScript.RegScript(this.Page, UpdatePanel1, "tipsWindown('提示信息','text:保存失败!','250','150','true','1000','true','text');");
            }
        }

 每个操作前都加这样的代码,还要输入每个操作对于权值的指数部分,如代码中的,1,2,3(1,2,3,4分别表示:查,增,修改,删除,其他根据操作项目面定),这样每个系统下来都要用个半天来作这些个简单,重复的事儿,再此真心希望大家给点优化的意见

  接下可能是我自己认为比较核心的部分吧,那就是如果判断当前登录的管理员,是否有权限进行当前操作,因为每个操作的权值都2的指数次方,所有我是通过按位与来判断,代码如下:

判断权限代码
/// <summary>
    /// 操作权限判断,返回0表示不能操作,1表示可以操作 1,2,3,4分别表示:查,增,修改,删除,其他根据操作项目面定
    /// </summary>
    /// <param name="model">当前登录用户</param>
    /// <param name="type">1,2,3,4分别表示:查,增,修改,删除</param>
    /// <param name="Permission">需要要的权限</param>
    public static int checkOperator(int type)
    {
        Hangjing.Model.EAdminInfo model = UserHelp.GetAdmin();
        int rs = 0;
        if (model != null)
        {
            if (model.Permission == "0")
            {
                string filename = GetUrlFileName();//获取页面名称,权限中是根据页面名称来获取模块,从而判断
                IList<sys_RolePermissionInfo> rplist = SectionProxyData.GetRolePermissions(model.Rem);//根据角色获取所有相关的模块项目
                int p_value = 0;
                //根据文件名获取当前所在的模块(一个模块包含涉及的页面,可能是多个)
                System.Globalization.CompareInfo Compare = System.Globalization.CultureInfo.InvariantCulture.CompareInfo;
                foreach (sys_RolePermissionInfo item in rplist)
                {
                    int i = Compare.IndexOf(item.des, filename, System.Globalization.CompareOptions.IgnoreCase);
                    if (item.des.IndexOf(filename) >= 0)
                    {
                        p_value = item.P_Value;
                        break;
                    }
                }
                if (p_value > 0)
                {
                    //此模块的权限值与当前操作 查(2),增(4),修改(8),删除(16)按位与,所得结果和操作的值一样,说明有这个操作权限
                    int cvalue = Convert.ToInt32(Math.Pow(2, type));
                    if ((p_value & cvalue) == cvalue)
                    {
                        rs = 1;
                    }
                }
            }
            else
            {
                rs = 1;
            }
        }
        if (rs == 0)
        {
            if (type == 1)
            {
                HttpContext.Current.Response.Redirect("~/basic.aspx?msg=1");
            }
        }
        return rs;
    }

    从早上7:00到下午13:30,终于完成第一篇博客了,不知不觉中就用了几个小时。写是写完了,不过我想,这样肯定对没有了解过权限的园友来说,看起来可能有些麻烦了,对了解权限的园友来说,可能又是不屑一顾的,有点纠结,主要是没法让大家看下效果,亲自体验下,不过,所有截图都是实际项目中的,关键操作流程有截图说明了。

  鄙人第一次写博客,各样操作都不是很熟悉,写得不好,大家海涵,如果这篇文章辱了园子名声,下篇:《订餐系统之按距离[根据经纬度]排序,搜索》定要为园子挽回点名声。  

   

    成为一名优秀的程序员!

posted @ 2013-05-11 14:30  2J  阅读(5409)  评论(52编辑  收藏  举报