95992828九五至尊2

Web开发框架之权能管理体系,Winform开发框架之权能管理系列的革新

二月 22nd, 2019  |  882828九五至尊手机版

纪念作者在很早此前,起始介绍自个儿的Winform开发框架和本人的WCF开发框架之初,作者一度提交下边的视图,介绍本身收拾的一个框架连串,其中蕴涵有WInform开发框架以及自小编的Web开发框架,由于前段时间向来缠身Winform开发框架的提炼以及优化,并联合整治了众多Winform开发框架以及WCF开发框架的小说小说。随着小编的Winform逐步健全,终于有时光来打点介绍作者的Web开发框架的事务了,上面先介绍一下本人最新优化整治的Web开发框架之权能管理系列,其中这一个权力管理种类能够说是集众多偏爱于寥寥了,除了固定的和代码生成工具集成,可变通基础性的框架代码外,还整合Winform开发框架继承而来的绝超越八分之四据库支持,在界面层,也等于Web权限管理种类,整合了JQuery的Easy-UI界面组件,功效强大的zTree控件、KindEditor在线编辑控件、界面层获取数据及保存使用基于JQuery的json数据操作,已毕数量局地刷新等等操作,其中提供三种区其余菜系布局操作,相当有利使用于任何工作系统的界面。

权力管理种类,从来是比比皆是Mis系统和一部分广大的管住连串所必要的,所以一般可以看成单身的模块进行开发,要求的时候举行整合即可,不须要每趟初始开发,除非至极的系统须求。作者在Winform开发框架介绍中的散文中,很早从前在《Winform开发框架之权能管理系列》就写过关于自己的通用权限管理体系的一些介绍,当时以此本子的要么古板样式的,界面如下所示。

882828九五至尊手机版 1

882828九五至尊手机版 2 

先是在介绍以前,大家来贴多少个Web权限系统的图形举办感性的打听先。

882828九五至尊手机版,鉴于本人的Winform开发框架须求,作者把权力管理种类、字典管理模块、分页控件等都扩大了支持古板样式、DotNetBar控件样式,以及DevExpress控件样式。这么些样式的界面此前也早已介绍不少了,本文首要介绍使用DevExpress控件样式的权杖管理体系,对一部分新的功能伸张以及周到,包涵系统项目管理、菜单管理、功效管理、登陆日志管理等模块举行介绍。

1)简洁的界面布局功用。那种效益顶部横幅相比较紧密,左侧有一部分常用的按钮操作,适合于菜单成效不太多的小事情系统,如自个儿的Web权限系统。

本权限管理种类包蕴用户管理、协会机构管理、角色管理、系统类型定义、作用管理、菜单管理、用户登录日志管理,以及对相应对象的权能决定管理等作用。整个权限管理种类是根据RBAC(基于角色的访问控制)格局开展权力决定,是三个独立的权杖管理系列,要求的时候工作系统与之进行整合即可,达成通用模块的快捷利用和联合保管等方面。

882828九五至尊手机版 3

壹 、系统项目管理

系统项目,是我们在权力系统中定义的七个系统分类,对于不相同的系统,大家透过这么些概念举行区分,可以兑现四个工作系统的军事管制(即使一般情况下,大家只是管理四个连串)。系统项目管理界面如下所示。

882828九五至尊手机版 4

本条目标的军事管制,此前一直在权力系统中,通过修改数据库举行伊始化,可是作者以为把它看成1个独自的数码举办保证,然后为意义定义、菜单、登陆日志等和种类项目涉及的多少举行安装管理,应该是比较便宜的。

因为,功效定义是基于有个别系统而扩充的一各种效能决定ID的概念,方便完毕按钮级别和数据级其他权能决定的基本功。

食谱的定义,是用来促成基于动态配置效率模块的菜谱,引入该模块的初衷是用来便于动态配置Winform恐怕Web的法力菜单,这些也是差其余系列肯定有两样的食谱了。

登陆日志管理,是用来便于记录来自业务系统对权限系统接口的主要性接口调用的记录,如登⑥ 、修改密码等操作,一般景观下,我们用不一样的政工体系来区分它们的数量。

2)功效强大的界面集团工作系统布局。那种界面效果适合于成效比较众多,菜单突显进行分类管理等事情系统。那种框架顶部的菜谱为拔尖菜单,单击一级菜单可以在左手展示二级菜单,那种效应可以毫无2遍性列出全部系统的职能,而是分层次开展功用显示。

二 、菜单管理

刚刚说到,那里的菜系管理,是指用来兑现基于动态配置作用模块的食谱,用来贯彻基于Winform、Web菜单的三合一统一,对于不相同的系统,菜单定义是例外的,因而他们是基于有些系统项目上边的数额管理。

为了实用管理菜单数据,小编把菜单的关联用树形控件举办浮现,并透过SplitContainer控件完结布局的创制切分,可以兑现自由拖动,界面效果如下所示。

882828九五至尊手机版 5

菜单的数量显示,右边使用了树形控件,数据经过递归方式开展绑定。右侧数据是经过自小编的分页控件进行数据绑定,并且绑定的多少是因此了层级的缩进格式化了的。

树菜单绑定的宗旨递归代码如下所示。

        /// <summary>
        /// 绑定树形数据
        /// </summary>
        private void InitTree()
        {
            treeView1.Nodes.Clear();
            treeView1.BeginUpdate();
            Cursor.Current = Cursors.WaitCursor;

            //先获取系统类型,然后对不同的系统类型下的菜单进行绑定显示
            List<SystemTypeInfo> typeList = BLLFactory<SystemType>.Instance.GetAll();
            foreach (SystemTypeInfo typeInfo in typeList)
            {
                TreeNode pNode = new TreeNode();
                pNode.Text = typeInfo.Name;//系统类型节点
                pNode.Name = typeInfo.OID;
                pNode.ImageIndex = 0;
                pNode.SelectedImageIndex = 0;
                this.treeView1.Nodes.Add(pNode);

                string systemType = typeInfo.OID;//系统标识ID

                //绑定树控件
                //一般情况下,对Ribbon样式而言,一级菜单表示RibbonPage;二级菜单表示PageGroup;三级菜单才是BarButtonItem最终的菜单项。
                List<MenuNodeInfo> menuList = BLLFactory<SysMenu>.Instance.GetTree(systemType);
                foreach (MenuNodeInfo info in menuList)
                {
                    TreeNode item = new TreeNode();
                    item.Name = info.ID;
                    item.Text = info.Name;//一级菜单节点
                    item.Tag = info;//对菜单而言,记录其MenuNodeInfo到Tag中,作为判断依据
                    item.ImageIndex = 1;
                    item.SelectedImageIndex = 1;
                    pNode.Nodes.Add(item);

                    AddChildNode(info.Children, item);
                }
            }

            Cursor.Current = Cursors.Default;
            treeView1.EndUpdate();
            this.treeView1.ExpandAll();
        }

        private void AddChildNode(List<MenuNodeInfo> list, TreeNode fnode)
        {
            foreach (MenuNodeInfo info in list)
            {
                TreeNode item = new TreeNode();
                item.Name = info.ID;
                item.Text = info.Name;//二、三级菜单节点
                item.Tag = info;//对菜单而言,记录其MenuNodeInfo到Tag中,作为判断依据
                int index = (fnode.ImageIndex + 1 > 3) ? 3 : fnode.ImageIndex + 1;
                item.ImageIndex = index;
                item.SelectedImageIndex = index; 
                fnode.Nodes.Add(item);

                AddChildNode(info.Children, item);
            }
        }

食谱的列表数据,通过分页控件绑定的代码如下所示。

        /// <summary>
        /// 根据查询条件构造查询语句
        /// </summary> 
        private string GetConditionSql()
        {
            SearchCondition condition = new SearchCondition();
            condition.AddCondition("Name", this.txtName.Text, SqlOperator.Like);
            condition.AddCondition("FunctionId", this.txtFunctionId.Text, SqlOperator.Like);
            condition.AddCondition("Visible", this.txtVisible.Checked ? 1 : 0, SqlOperator.Equal);
            condition.AddCondition("WinformType", this.txtWinformType.Text, SqlOperator.Like);
            condition.AddCondition("Url", this.txtUrl.Text, SqlOperator.Like);

            string where = condition.BuildConditionSql().Replace("Where", "");

            return where;
        }

        /// <summary>
        /// 绑定列表数据
        /// </summary>
        private void BindData()
        {
            //entity
            this.winGridViewPager1.DisplayColumns = "Name,Icon,Seq,FunctionId,Visible,WinformType,Url";
            #region 添加别名解析

            this.winGridViewPager1.AddColumnAlias("ID", "");
            this.winGridViewPager1.AddColumnAlias("Name", "显示名称");
            this.winGridViewPager1.AddColumnAlias("Icon", "图标");
            this.winGridViewPager1.AddColumnAlias("Seq", "排序");
            this.winGridViewPager1.AddColumnAlias("FunctionId", "功能ID");
            this.winGridViewPager1.AddColumnAlias("Visible", "菜单可见");
            this.winGridViewPager1.AddColumnAlias("WinformType", "Winform窗体类型");
            this.winGridViewPager1.AddColumnAlias("Url", "Web界面Url地址");

            #endregion

            string where = GetConditionSql();
            List<MenuInfo> list = BLLFactory<SysMenu>.Instance.FindWithPager(where, this.winGridViewPager1.PagerInfo);
            list = CollectionHelper<MenuInfo>.Fill("-1", 0, list, "PID", "ID", "Name");
            this.winGridViewPager1.DataSource = new WHC.Pager.WinControl.SortableBindingList<MenuInfo>(list);
            this.winGridViewPager1.PrintTitle = "功能菜单信息报表";
        }

食谱的编排界面如下所示。

882828九五至尊手机版 6

本篇紧假使介绍菜单的管制,对于菜单的动态加载管理,作者会在此外一篇Winform开发框架中展开介绍。菜单定义数据里面的法力控件ID,是源于作用模块的法力控件ID,是用来决定不同用户所能访问的菜系能源的。

882828九五至尊手机版 7顶部的Tab选项卡每一遍打开页面的时候,伸张一个Tab页,页面可以双击进行关闭,也可以右键弹出菜谱进行越来越多操作,如下图所示。

③ 、功用管理

效果定义,也是依据有些系统项目下边的,对于不一样的作业系统,大家能够集中放在两个权力管理体系里面举行管制,不过效果的定义,依照不一样的系列项目举行区分即可,那样的目标是用来贯彻各个公司应用的实用整合。

功用的田间管理,是漫天权限系统的着力,因为经过对她们的概念,以及权限分配,都会影响各类角色用户可访问的效益;功用定义的数目,其实也是贰个树形结构,可以用树控件举行展示出来,如下所示。

882828九五至尊手机版 8

 

882828九五至尊手机版 9

④ 、日志管理

我们了解,一般权限系统,管理用户很广泛的,由此用户的登陆日志,一般景观下是由权力管理系列记录即可,
如每一回用户登陆的时候,我们记录用户的登陆日志;假诺用户修改密码,大家也做多个主要记录,那样对于在事情序列端的管理,大家就不须要管理他们的登陆方面的轩然大波了。

日志管理分为五个部分,贰个是因而权限管理连串本人的报到入口进行登录的,三个是经过与之集成的事情种类,通过API调用格局展开登录验证的,
他们的报到接口基本一致,只是一些数据不同。

            try
            {
                //判断用户是否登录成功
                string ip = NetworkUtil.GetLocalIP();
                string macAddr = HardwareInfoHelper.GetMacAddress();

                string identity = BLLFactory<User>.Instance.VerifyUser(this.txtLogin.Text, this.txtPassword.Text, "WareMis", ip, macAddr);
                if (!string.IsNullOrEmpty(identity))
                {
                    //进一步判断用户角色
                    if (BLLFactory<User>.Instance.UserInRole(this.txtLogin.Text, RoleInfo.AdminName))
                    {
                        MessageUtil.ShowTips(string.Format("用户【{0}】身份验证正确", this.txtLogin.Text));
                    }
                    else
                    {
                        MessageUtil.ShowWarning("该用户没有管理员权限");
                        return;
                    }
                }
                else
                {
                    MessageUtil.ShowWarning("用户名或密码错误");
                    return;
                }
            }
            catch (Exception err)
            {
                MessageUtil.ShowError(err.Message);
            }

权力管理系统对日志举办统一管理和浮现,具体界面如下所示。

882828九五至尊手机版 10

全体权限管理体系,目标升高系统开发速度和频率,因而通过单独开发,模块重用,易于集成等措施贯彻大家生儿育女功效的最大化。

如若急需精通任何系列的效率,也可以下载《Web权限系统操作视屏》进行完善的摸底。

在提炼优化这一个Web权限框架的历程中,遇到了众多的标题,一一举办缓解,现总括一部分举办进行介绍。

1)使用JSON数据构造zTree

动用zTree确实比easy-ui自带的Tree好过多,功用也有力很多,由于自个儿的Web权限中,各种模块大致都要求树控件来显示相关的数额,如效果、社团部门等等。在自查自纠了自家本人的古板Tree、Easy-UI的Tree控件以及zTree后,发现选取zTree依旧得以增进广大的界面分数的。但是其自带的例子,以及网上的例证,多数是应用预先弄好的树形数据,而本身必要动态使用ashx进行树形数据的拿到及变更,那确实费了一部分坎坷来拓展调试。

第1要准备依照ashx处理程序生成的Tree数据,树的数码应用JSON格式。如效果定义的树形数据如下所示。

        /// <summary>
        /// 递归获取树形信息
        /// </summary>
        private string GetTreeJson(int PID, string folderIcon, string leafIcon)
        {
            string condition = string.Format("PID={0}", PID);
            List<FunctionInfo> nodeList = BLLFactory<Function>.Instance.Find(condition);
            StringBuilder content = new StringBuilder();
            foreach (FunctionInfo model in nodeList)
            {
                int ParentID = (model.PID == -1 ? 0 : model.PID);
                //string tempMenu = string.Format("{{ id:{0}, pId:{1}, name:\"{2}\",icon:\"{3}\" }},", model.ID, ParentID, model.Name, imgsrc); //简单的作法
                string subMenu = this.GetTreeJson(model.ID, folderIcon, leafIcon);
                string parentMenu = string.Format("{{ \"id\":{0}, \"pId\":{1}, \"name\":\"{2}\" ", model.ID, ParentID, model.Name);
                if (string.IsNullOrEmpty(subMenu))
                {
                    if (!string.IsNullOrEmpty(leafIcon))
                    {
                        parentMenu += string.Format(",\"icon\":\"{0}\" }},", leafIcon);
                    }
                    else
                    {
                        parentMenu += "},";
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(folderIcon))
                    {
                        parentMenu += string.Format(",\"icon\":\"{0}\" }},", folderIcon);
                    }
                    else
                    {
                        parentMenu += "},";
                    }
                }

                content.AppendLine(parentMenu.Trim());
                content.AppendLine(subMenu.Trim());
            }

            return content.ToString().Trim();
        } 

下一场就是页面的调用了,那里为了加强体验效果,使用了基于javascript的JQuery的异步操作举行数据处理,而不是根据aspx后台页面的拍卖,如下所示。

        //重新加载树形结构(异步)
        function reloadTree() {
            $("#loading").show();
            $.getJSON("http://www.cnblogs.com/AjaxHandler/FunctionJson.ashx?r=" + Math.random() + "&op=tree", function (json) {
                $.fn.zTree.init($("#treeDemo"), setting, json);
                $.fn.zTree.getZTreeObj("treeDemo").expandAll(true);

                var treeObj = $.fn.zTree.getZTreeObj("treeDemo");
                var treeNodes = treeObj.getNodes();
                if (treeNodes != null) {
                    loadData(treeNodes[0].id);
                }
            });
            $("#loading").fadeOut(500);
        }

那样处理的功力是页面只是有些刷新,体验很好。

2)基于JQuery的数码加载及保存操作

由于JQuery的方便性及非凡体验性,小编联合了数额的拿到及保存操作。上面给出相关的拍卖代码供参考。

        //加载制定的对象数据
        function loadData(id) {
            $("#loading").show();
            $.getJSON("http://www.cnblogs.com/AjaxHandler/FunctionJson.ashx?r=" + Math.random() + "&op=findbyid&id=" + id, function (json) {
                $("#txtID").val(json.ID);
                $("#txtName").val(json.Name);
                $("#txtControlID").val(json.ControlID);
                $("#txtPID").val(json.PID);
            });

            $('#lbxRoles').empty();
            $.getJSON("http://www.cnblogs.com/AjaxHandler/RoleJson.ashx?r=" + Math.random() + "&op=getrolesbyfunction&id=" + id, function (json) {
                $.each(json, function (i, item) {
                    $('#lbxRoles').append('<option value="' + item.ID + '">' + item.Name + '</option>');
                });
            });
            $("#loading").fadeOut(500);
        }

        //保存对象数据
        function saveData() {
            $.ajax({
                type: 'POST',
                url: 'http://www.cnblogs.com/AjaxHandler/FunctionJson.ashx?r=' + Math.random() + '&op=insert',
                async: false,
                data: { ID: $("#txtID").val(), Name: $("#txtName").val(), ControlID: $("#txtControlID").val(), PID: $("#txtPID").val() },
                success: function (id) {
                    alert("操作成功! ");
                    reloadTree();

                    if (id != "")
                        loadData(id);
                },
                error: function (xhr, status, error) {
                    alert("操作失败"); //xhr.responseText
                }
            });
        }

3)在数码操作等待的时候,页面中间展现Loading效果。

漫天系列,在种种请求操作,小编都合并了作法,在界面展现Loading的等待效果,职分完结后关门,那种效果在劳动的操作,用户体检会好一些,上面看看其成效以及落到实处代码。

882828九五至尊手机版 11

日增上边javascript脚本

        //对象居中的函数,调用例子:$("#loading").center();
        jQuery.fn.center = function () {
            this.css("position", "absolute");
            this.css("top", Math.max(0, (($(window).height() - this.outerHeight()) / 2) +
                                                $(window).scrollTop()) + "px");
            this.css("left", Math.max(0, (($(window).width() - this.outerWidth()) / 2) +
                                                $(window).scrollLeft()) + "px");
            return this;
        }

        //初始化对象
        $(document).ready(function () {

            $("#loading").center();//loading的图片显示居中
        });

然后再页面Body前边扩张一行代码即可(暗中同意loading图片不显得的哦)。

    <div id="loading" style="display: none;"><img alt="数据正在加载中..." src="http://images.cnblogs.com/loading02.gif" /></div>

4)控件数据清空操作

鉴于添加和编制公用界面控件成分,由此我们在要添加多少的时候,须要清空恐怕设置有些控件的值,但大家的控件只怕对比多,一种好的主意是接纳JQuery的采用器成效来举行有目的的控件清空操作。

如上边的例证所示。

        //新增清空控件
        function addData() {
            $("#txtPID").val($("#txtID").val());
            $("input[type=text][id*='txt']").val("");
            $("textarea[id*='txt']").empty();
            $("select[id*='lbx']").empty();
        }

其中$(“#txtPID”).val($(“#txtID”).val());是把近来的用户作为丰盛数量的上级,其他的就是清空控件的数量了,不一样的档次控件清空的步子某些不一致。

5)Ashx处理程序的安全性考虑

大家在系统中,多数都以调用ashx进行数量处理,即便一般工作系统在VPN或许内网中运维,不过也要考虑用户没登陆的时候,不运营调用ashx程序,那样可以增进多少的安全性。

私自认同的ashx处理程序是没有Session的操作的,所以我们必要修改其后续接口(多扩充IReadOnlySessionState 的后续)

,然后才能调用Session来展开判定。

    /// <summary>
    /// 权限功能操作类
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class FunctionJson : IHttpHandler, IReadOnlySessionState 
    {        
        public void ProcessRequest(HttpContext context)
        {
            //类对象要显式的实现接口 IReadOnlySessionState,才能访问Session数据
            if (context.Session["Identity"] == null)
            {
                throw new ArgumentException("用户未登录!");
            }

6)Tab界面布局的格外。

Web权限系统提供了两种常用的菜单布局举办管制,一般对于常用的事体系列肯定是没难点了。

882828九五至尊手机版 12

别的一种效应是系统错综复杂的时候用的,可以定义一级菜单和事关的二级菜单。

882828九五至尊手机版 13

对于后者,顶级菜单打开的时候,可以提到打开1个新的页面,并且刷新二级菜单的关联。

        <!----------- 一级导航 ------------------>
        <ul class="navigation" style="display:block">
            <li><a href="#" onclick="showSubMenu('ListUser.aspx', '用户管理', 'default')">权限管理</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/MyJob.aspx', '事务中心开发中...', 'point', 'icon-organ')">事务中心</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/building.htm', '合同起草开发中...', '')">合同起草</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/building.htm', '合同管理开发中...', '')">合同管理</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/building.htm', '查询打印开发中...', '')">查询打印</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/building.htm', '知识管理开发中...', '')">知识管理</a></li>
            <li><a href="#" onclick="showSubMenu('../Commonpage/building.htm', '系统管理开发中...', '')">系统管理</a></li>
        </ul>

 好了,很多任何的风味,以往继续介绍,欢迎多多提议宝贵意见。

相关文章

Your Comments

近期评论

    功能


    网站地图xml地图