欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

程序员文章站 2022-05-08 14:34:05
...

经典权限解决方案

1.权限简介
一般的管理系统都需要对用户的操作进行一定的限制,有的用户可以有许多操作,有的则有少量的操作.这样就需要一个授权机制,基于角色的授权机制描述了某个角色拥有一定数量的操作授权,属于该角色的用户则也就拥有了该角色的权限,且若用户属于多个角色则其拥有多个角色权限的集合.
我们的权限精确到按钮级别,如共享文档管理,管理可以查询、上传文档、下载文档、删除文档等操作,而一般的用户只需要查询和下载文档就可以了,
这时候我们的权限管理就发挥了作用, 下面让我们一步步开始实现!
我们使用ASP.NET结合jQuery、EasyUI实现一个精典的权限管理机制

2.数据模型设计
数据模型包括:员工表,角色表,员工与角色关系表和角色权限表
员工表: 员工登录到系统,如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

角色表:授权权限的集合对象,如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

角色表与员工关系表:如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

角色权限表:如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

3.Action定义
用户对应某功能的操作(如:增\删\改\查)需要一一建立相应操作行为实例(Action),这里以”文档管理”为例: 变量代表文档管理中的单个操作,例如 Directory_add = “j”;代表添加文档操作,其他各操作定义如下:

        public static string Directory_browse = "i";//文档浏览操作
        public static string Directory_add = "j";//文档浏览添加
        public static string Directory_update = "k";//文档浏览修改
        public static string Directory_delete = "l";//文档浏览删除

定义文档操作Action: 每个Action有标题(text)、图标(iconCls)、处理函数(handler),如下:

    /// <summary>
    /// 文档操作Action
    /// </summary>
    public class DocActions
    {
        public static ToolbarItem Query = new ToolbarItem()
        {
            text = "查询",
            iconCls = "icon-search",
            handler = "oa.os.doc.onBtnQueryDocClick"
        };
        public static ToolbarItem Refresh = new ToolbarItem()
        {
            text = "刷新",
            iconCls = "icon-reload",
            handler = "oa.os.doc.onBtnRefreshDocClick"
        };
        public static ToolbarItem Upload = new ToolbarItem()
        {
            text = "上传文档",
            iconCls = "icon-add",
            handler = "oa.os.doc.onBtnUploadDocClick"
        };
        public static ToolbarItem Update = new ToolbarItem()
        {
            text = "编辑",
            iconCls = "icon-application_edit",
            handler = "oa.os.doc.onBtnEditDocClick"
        };
        public static ToolbarItem Delete = new ToolbarItem()
        {
            text = "删除",
            iconCls = "icon-delete",
            handler = "oa.os.doc.onBtnDelDocClick"
        };
    }

4.给角色授权, 结合EasyUI数据表格组件,效果如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

勾选复选框就表示为该角色授权其他的操作

权限目录树的初始化,如下(在AppPermission.cs类)

        /// <summary>
        /// 初始化权限目录树
        /// </summary>
        /// <returns></returns>
        private static PermTreeNode[] CreatePermission()
        {
            PermTreeNode[] nodes = new PermTreeNode[]{
                new PermTreeNode() { 
                    Name = "系统权限",Id="",
                    children = new PermTreeNode[]{
                        new PermTreeNode()
                        {                  
                            Name = "个人办公",
                            children=new PermTreeNode[]{
                                new PermTreeNode()
                                {
                                    Name = "个人考勤",
                                    Action1 = new PermAction() { Name = "个人考勤管理", Action = AppAction.PunchInOut }
                                },                                                                
                                new PermTreeNode()
                                {
                                    Name = "工作日志",
                                    Action1 = new PermAction() { Name = "工作日志管理", Action = AppAction.WorkLog }
                                }
                            }
                        },
                        new PermTreeNode()
                        {                  
                            Name = "人事管理",
                            children=new PermTreeNode[]{
                                new PermTreeNode()
                                {
                                    Name = "部门管理",
                                    Action1 = new PermAction() { Name = "添加", Action = AppAction.Department_add },
                                    Action2 = new PermAction() { Name = "编辑", Action = AppAction.Department_update },
                                    Action3 = new PermAction() { Name = "删除", Action = AppAction.Department_delete }
                                },                                                                
                                new PermTreeNode()
                                {
                                    Name = "员工管理",
                                    Action1 = new PermAction() { Name = "浏览", Action = AppAction.Employee_browse },
                                    Action2 = new PermAction() { Name = "添加", Action = AppAction.Employee_add },
                                    Action3 = new PermAction() { Name = "编辑", Action = AppAction.Employee_update },
                                    Action4 = new PermAction() { Name = "删除", Action = AppAction.Employee_delete }
                                }
                            }
                        },
                        new PermTreeNode()
                        {                  
                            Name = "文档管理",
                            children=new PermTreeNode[]{
                                new PermTreeNode()
                                {
                                    Name = "目录管理",
                                    Action1 = new PermAction() { Name = "添加", Action = AppAction.Directory_add },
                                    Action2 = new PermAction() { Name = "编辑", Action = AppAction.Directory_update },
                                    Action3 = new PermAction() { Name = "删除", Action = AppAction.Directory_delete }
                                },                                                                
                                new PermTreeNode()
                                {
                                    Name = "文档管理",
                                    Action1 = new PermAction() { Name = "浏览", Action = AppAction.Document_browse },
                                    Action2 = new PermAction() { Name = "添加", Action = AppAction.Document_add },
                                    Action3 = new PermAction() { Name = "编辑", Action = AppAction.Document_update },
                                    Action4 = new PermAction() { Name = "删除", Action = AppAction.Document_delete }
                                }
                            }
                        },
                        //系统管理
                        new PermTreeNode()
                        {
                            Name = "系统管理",
                            children=new PermTreeNode[]{
                                new PermTreeNode()
                                {
                                    Name = "角色管理",
                                    Action1 = new PermAction() { Name = "浏览", Action = AppAction.Role_browse },
                                    Action2 = new PermAction() { Name = "添加", Action = AppAction.Role_add },
                                    Action3 = new PermAction() { Name = "编辑", Action = AppAction.Role_update },
                                    Action4 = new PermAction() { Name = "删除", Action = AppAction.Role_delete }
                                },
                                new PermTreeNode()
                                {
                                    Name = "操作日志管理",
                                    Action1 = new PermAction() { Name = "浏览", Action = AppAction.OperatLog }
                                }
                            }                                
                        }
                    }
                }   
            };

            InitSystemPerm(nodes);
            return nodes;
        }

Role.js加载角色列表,如下

    f.prototype.queryRole=function(toolbar){
        $(datagridId).datagrid({
            url:'Handler/RoleHandler.ashx?Action=GetRoles',
            idField:'Id',
            rownumbers:true,
            singleSelect:true,
            checkOnSelect:false,
            selectOnCheck:false,
            pagination:true,
            pageSize:20,fitColumns:true,
            sortName:'Name',
            //onClickRow:onClickRow,
            onClickCell: onClickCell,
            onAfterEdit: onAfterEdit,            
            view: detailview,
            toolbar:toolbar,
            columns:[[
                {field:'ck',checkbox:true},
                {
                    title:'角色名称',field:'Name',sortable:true,width:150,
                    formatter:function(value, row, index){
                        return value && value.length > 8 ? '<span title="' + value + '">' + value + '</span>' : value;
                    },
                    editor:{type:'textbox',options:{required:true,missingMessage:'请输入角色名称'}}
                },
                {
                    title:'角色描述',field:'Remark',sortable:true,width:800,
                    formatter:function(value, row, index){
                        return value && value.length > 20 ? '<span title="' + value + '">' + value + '</span>' : value;
                    },
                    editor:'textbox'
                }
            ]],
            detailFormatter:function(index,row){
                //return '<div style="padding:2px"><ul class="ddv"></ul></div>';
                return '<div style="padding:2px"><table class="ddv"></table></div>';
            },
            onExpandRow: function(index,row){
                var roleIndex=index;
                var roleId=row.Id;
                var ddv = $(this).datagrid('getRowDetail',index).find('table.ddv');
                ddv.treegrid({    
                    url:'Handler/AuthorHandler.ashx?Action=GetRolePerms&RoleId='+row.Id,    
                    idField:'Id',    
                    treeField:'Name',  
                    lines:true,  
                    columns:[[    
                        {title:'系统权限设置',field:'Name',width:200,
                            formatter: function(value,row,index){
                                return '<input type="checkbox" roleId='+roleId+' permId='+row.Id+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+row.Checked+' onclick="oa.os.perm.onNodeCheckboxClick(this)" />'+value;
                            }
                        },    
                        {field:'Action1',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action2',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action3',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action4',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action5',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action6',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action7',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action8',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action9',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        },
                        {field:'Action10',title:'',width:100,
                            formatter: function(value,row,index){
                                if(value && value.Name){
                                    return '<input type="checkbox" roleId='+roleId+' action='+value.Action+' roleindex="'+roleIndex+'" path="'+row.Path+'" '+value.Checked+' onclick="oa.os.perm.onCheckboxClick(this)" />'+value.Name;
                                }
                            }
                        }
                    ]] ,
                    onResize:function(){
                        $(datagridId).datagrid('fixDetailRowHeight',index);
                    },
                    onCollapse:function(row){
                        $(datagridId).datagrid('fixDetailRowHeight',index);
                    },
                    onExpand:function(row){
                        $(datagridId).datagrid('fixDetailRowHeight',index);
                    },
                    onLoadSuccess:function(){
                        setTimeout(function(){
                            $(datagridId).datagrid('fixDetailRowHeight',index);
                        },0);
                    }
                }); 
                $(datagridId).datagrid('fixDetailRowHeight',index);
            }
        });
    };

勾选/去掉勾选相应的操作复选框以保存该角色的该操作权限:
JS:

var saveRolePermAction=function(roleId,action,checked,fn){
        $.ajax({
            url: "Handler/AuthorHandler.ashx",
            data: {Action:'SaveRolePermAction',RoleId:roleId,Actions:action,Checked:checked},
            type: "get",
            dataType: "json",
            success: function (data) {
                if (data.success) {
                    if(fn){
                        fn();
                    }
                }else{
                    $.messager.alert("错误",data.msg,"error");
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                if (textStatus == "timeout") {
                    $.messager.alert("提示", "请求超时,请刷新当前页重试!");
                }
                else {
                    $.messager.alert("错误", textStatus + ":" + errorThrown);
                }
            }
        });
    };

AuthorHandler.ashx.cs :

public string SaveRolePermAction(HttpRequest request)
        {
            string response = string.Empty;
            try
            {
                SaveRolePermActionRequestParam param = RequestParamHandler.GetParam<SaveRolePermActionRequestParam>(request);
                bool flag = AuthorController.SaveRolePermissionAction(param.RoleId, param.Actions, param.Checked);
                if (flag)
                {
                    response = "{\"success\":true,\"msg\":\"保存成功\"}";
                }
                else
                {
                    response = "{\"success\":false,\"msg\":\"保存失败!\"}";
                }
            }
            catch (RequestParamException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw;
            }
            return response;
        }

AuthorController.cs :

/// <summary>
        /// 保存指定角色指定操作的授权
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="action"></param>
        /// <param name="check"></param>
        /// <returns></returns>
        public static bool SaveRolePermissionAction(int roleId, string action, bool check)
        {
            return SaveRolePermission(roleId, new string[] { action }, check);
        }

        /// <summary>
        /// 保存指定角色指定操作的授权
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="actions"></param>
        /// <param name="check"></param>
        /// <returns></returns>
        private static bool SaveRolePermission(int roleId, string[] actions, bool check)
        {
            return Permission.SaveRolePermission(roleId, actions, check);
        }

OA.BLL.Permission.cs :

/// <summary>
        /// 保存角色权限
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="actions"></param>
        /// <param name="isChecked"></param>
        /// <returns></returns>
        public static bool SaveRolePermission(int roleId, string[] actions, bool isChecked)
        {
            return dal.SaveRolePermission(roleId, actions, isChecked);
        }

OA.SQLServerDAL.Permission.cs :

        /// <summary>
        /// 保存角色权限
        /// </summary>
        /// <param name="roleId"></param>
        /// <param name="actions"></param>
        /// <param name="isChecked"></param>
        /// <returns></returns>
        public bool SaveRolePermission(int roleId, string[] actions, bool isChecked)
        {
            StringBuilder sql = new StringBuilder();
            if (isChecked)
            {
                if (actions.Length > 0)
                {
                    ArrayList sqlList = new ArrayList();
                    IList<DbParameter[]> parmList = new List<DbParameter[]>();
                    SqlParameter[] parm = new SqlParameter[1];
                    foreach (string item in actions)
                    {
                        parm = new SqlParameter[2];
                        parm[0] = new SqlParameter("@RoleId", SqlDbType.Int);
                        parm[0].Value = roleId;
                        parm[1] = new SqlParameter("@Action", SqlDbType.VarChar, 64);
                        parm[1].Value = SQLHelper.Escape(item);

                        sqlList.Add("proc_PermissionOfRoleInsert");
                        parmList.Add(parm);
                    }
                    SQLHelper.ExecuteTranByProcedure(sqlList, parmList);
                }
            }
            else
            {
                string actionStr = SQLHelper.ConverArrayToStringArray(actions);
                sql.Append("delete from RolePermission where RoleId='").Append(roleId).Append("' and Action in(").Append(actionStr).Append(")");
                SQLHelper.Update(sql.ToString());
            }
            return true;
        }
    }

存储过程: proc_PermissionOfRoleInsert

--创建添加角色权限存储过程
if exists(select * from sysobjects where type='p' and name='proc_PermissionOfRoleInsert')
begin
    drop procedure proc_PermissionOfRoleInsert  
end
go
create procedure proc_PermissionOfRoleInsert
(
    @RoleId int,
    @Action varchar(64)
)
as
    declare @e int
    set @e=0;
    select @e=1 from RolePermission where aaa@qq.com and aaa@qq.com;
    if(@e<1)
    begin
        insert RolePermission(RoleId,[Action],[Option]) values(@RoleId,@Action,1);
    end
go

保存结果如下图 :
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

5.新建员工,并为员工分配角色,如下图:
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

6.员工登录: 登录后获取员工基本信息和授权信息等保存在Cookie中,以后员工的每次操作都从Cookie中获取授权信息并以AOP方式进行权限验证,没有授权的操作以抛出权限异常的方式终止操作,以保护数据的安全
登录:
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

登录请求AuthHandler.ashx.cs

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private string SingIn(HttpRequest request)
        {
            AuthResponseParm resp = new AuthResponseParm();
            string response = string.Empty;
            try
            {
                AuthParm param = RequestParamHandler.GetParam<AuthParm>(request);
                IList<string> roles = null;
                IList<PermissionInfo> perms = null;
                EmployeeInfo employeeInfo = AuthController.Validate(param.UserName, param.Password, out roles, out perms);
                if (null != employeeInfo)
                {
                    resp.Flag = 1;

                    UserPrincipal userinfo = new UserPrincipal();
                    userinfo.UserId = employeeInfo.Id.ToString();
                    userinfo.UserName = param.UserName;
                    userinfo.Roles = roles;
                    if (null != perms && perms.Count > 0)
                    {
                        //userinfo.PermissionList = perms;
                        userinfo.Permissions = ConvertPermissionsToJson(perms.ToArray<PermissionInfo>());// new AuthorizationController().ConvertPermissionsToJson(parm.UserName);
                    }
                    // 登录状态1天或者7天内有效
                    int validDays = param.Valid7 ? 7 : 1;
                    FormsPrincipal<UserPrincipal>.SavePrincipalToCookie("Login", userinfo, validDays * 24 * 60);
                }
                else
                {
                    resp.Flag = 0;
                    resp.Msg = "用户名和密码错误,请重新输入.";
                }
            }
            catch (Exception ex)
            {
                resp.Flag = 0;
            }
            response = JsonHelper.JsonSerializer<AuthResponseParm>(resp);
            return response;
        }

其中 EmployeeInfo employeeInfo = AuthController.Validate(param.UserName, param.Password, out roles, out perms); 进行员工名和密码验证,并且返回该员工的授权信息

保存员工基本信息和授权信息在Cookie中:

        /// <summary>
        /// 保存用户信息到Cookie
        /// </summary>
        /// <param name="loginName">登录名</param>
        /// <param name="userData">与登录名相关的用户信息</param>
        /// <param name="expiration">登录Cookie的过期时间,单位:分钟。</param>
        public static void SavePrincipalToCookie(string loginName, TUserData userData, int expiration)
        {
            if (string.IsNullOrEmpty(loginName))
                throw new ArgumentNullException("loginName");
            if (userData == null)
                throw new ArgumentNullException("userData");

            // 1. 把需要保存的用户数据转成一个字符串。
            string data = null;
            if (userData != null)
                data = (new JavaScriptSerializer()).Serialize(userData);


            // 2. 创建一个FormsAuthenticationTicket,它包含登录名以及额外的用户数据。
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                2, loginName, DateTime.Now, DateTime.Now.AddDays(1), true, data);


            // 3. 加密Ticket,变成一个加密的字符串。
            string cookieValue = FormsAuthentication.Encrypt(ticket);


            // 4. 根据加密结果创建登录Cookie
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue);
            cookie.HttpOnly = true;
            cookie.Secure = FormsAuthentication.RequireSSL;
            cookie.Domain = FormsAuthentication.CookieDomain;
            cookie.Path = FormsAuthentication.FormsCookiePath;
            if (expiration > 0)
                cookie.Expires = DateTime.Now.AddMinutes(expiration);

            HttpContext context = HttpContext.Current;
            if (context == null)
                throw new InvalidOperationException();

            // 5. 写登录Cookie
            context.Response.Cookies.Remove(cookie.Name);
            context.Response.Cookies.Add(cookie);
        }

7.以文档管理为例讲解员工的授权,页面如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

新建文档管理index.html页面

<script src="Scripts/OS/Doc/Doc.js" type="text/javascript"></script>
<div class="easyui-layout" data-options="fit:true">
    <div data-options="region:'west',split:true,title:'地址导航'" style="width: 280px; padding: 0;border-left:0; border-bottom:0; border-top:0;">
        <div class="easyui-layout" data-options="fit:true">
            <div data-options="region:'north'" id="dirActionMbContain_doc" style="height:28px;border-top:0;border-left:0;border-right:0;">
                <a href="#" class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-arrow_out',onClick:oa.os.doc.expandAll"></a>
                <a href="#" class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-arrow_in',onClick:oa.os.doc.collapseAll"></a>
                <a href="#" class="easyui-linkbutton" data-options="plain:true,iconCls:'icon-arrow_refresh',onClick:oa.os.doc.reloadDirTree"></a>
            </div>
            <div data-options="region:'center',border:false">
                <ul id="tree_dir_doc">
                </ul>
            </div>
        </div>
    </div>
    <div data-options="region:'center'" style=" border-bottom:0; border-top:0;border-right:0;">
        <div id="tabs_doc_doc" class="easyui-tabs" data-options="fit:true,border:false">
            <div title="文档列表" data-options="iconCls:'icon-layout_sidebar'">
                <table id="grid_doc_doc" data-options="fit:true,border:false">
                </table>
            </div>
        </div>
    </div>
</div>
<div id="dirMenuButton_doc" style="width:150px;"></div>
<div id="dirContextMenu_doc" class="easyui-menu" style="width:150px;"></div>
<div id="toolbar_docDatagrid_doc" style="padding:3px;height:auto">
    文档名称: <input id="toolbar_name_docDatagrid_doc" class="easyui-textbox" data-options="" style="width:120px">
</div>

新建Global.asax

        /// <summary>
        /// http请求时从Cookie获取用户基本信息和授权信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_AuthenticateRequest(object sender, EventArgs e)
        {
            HttpApplication app = (HttpApplication)sender;
            FormsPrincipal<UserPrincipal>.TrySetUserInfo(app.Context);
        }

FormsPrincipal.cs

        /// <summary>
        /// 根据HttpContext对象设置用户标识对象
        /// </summary>
        /// <param name="context"></param>
        public static void TrySetUserInfo(HttpContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            FormsPrincipal<TUserData> user = TryParsePrincipal(context.Request);
            if (user != null)
                context.User = user;
        }

新建Doc.js文件:

    //获取用户授权的文档的操作按钮列表
    function loadDocDatagridActions(callback){
        $.ajax({
            url: "Handler/AuthorHandler.ashx",
            data: {Action:'GetDocActions'},
            type: "get",
            dataType: "json",
            success: function (data) {
                createDocDatagridToolbar(data);
                callback();
            }
        });
    };  

AuthorHandler.cs

    /// <summary>
      /// 获取用户授权的文档的操作按钮列表
      /// </summary>
      /// <param name="request"></param>
      /// <returns></returns>
      public string GetDocActions(HttpRequest request)
      {
          string response = "[]";
          try
          {
              ToolbarItem[] items = AuthorController.GetDocActions();
              return ParseToolbarToJson(items);
          }
          catch (RequestParamException ex)
          {
              throw ex;
          }
          catch (Exception ex)
          {
              throw;
          }
          return response;
      }

AuthorController.cs,如下

        /// <summary>
        /// 获取指定用户授权的文档的操作按钮列表
        /// </summary>
        /// <returns></returns>
        public static ToolbarItem[] GetDocActions()
        {
            FormsPrincipal<UserPrincipal> user = Authen.GetUser();
            if (null != user && !string.IsNullOrEmpty(user.UserData.Permissions))
            {
                string permStr = user.UserData.Permissions;
                IList<ToolbarItem> items = new List<ToolbarItem>();
                if (AppAction.IsEnableDocumentBrowse(permStr))
                {
                    items.Add(DocActions.Query);
                }
                if (AppAction.IsEnableDocumentAdd(permStr))
                {
                    items.Add(DocActions.Upload);
                }
                if (AppAction.IsEnableDocumentUpdate(permStr))
                {
                    items.Add(DocActions.Update);
                }
                if (AppAction.IsEnableDocumentBrowse(permStr))
                {
                    items.Add(DocActions.Refresh);
                }
                return items.ToArray();
            }
            return null;
        }

AppAction.cs 如下

    #region 判断文档操作权限
        /// <summary>
        /// 是否有文档浏览权限
        /// </summary>
        /// <param name="permissions"></param>
        /// <returns></returns>
        public static bool IsEnableDocumentBrowse(string permissions)
        {
            return EnableAction(permissions, Document_browse) || IsEnableDocumentAdd(permissions)
            || IsEnableDocumentUpdate(permissions) || IsEnableDocumentDelete(permissions);
        }
        /// <summary>
        /// 是否有添加文档的权限
        /// </summary>
        /// <param name="permissions"></param>
        /// <returns></returns>
        public static bool IsEnableDocumentAdd(string permissions)
        {
            return EnableAction(permissions, Document_add);
        }
        /// <summary>
        /// 是否有更新文档的权限
        /// </summary>
        /// <param name="permissions"></param>
        /// <returns></returns>
        public static bool IsEnableDocumentUpdate(string permissions)
        {
            return EnableAction(permissions, Document_update);
        }
        /// <summary>
        /// 是否有删除文档的权限
        /// </summary>
        /// <param name="permissions"></param>
        /// <returns></returns>
        public static bool IsEnableDocumentDelete(string permissions)
        {
            return EnableAction(permissions, Document_delete);
        }
    #endregion

得到文档操作的Action列表后,Doc.js创建文档列表Datagrid工具栏

    //创建文档列表Datagrid工具栏
    function createDocDatagridToolbar(toolbar){
        $(datagridId).datagrid({ toolbar: '#toolbar_docDatagrid_doc'});
        $(datagridId).datagrid("addToolbarItem",toolbar);
    }

jquery.easyui.extension.js 用以添加工具栏按钮

//扩展datagrid增加工具按键
$.extend($.fn.datagrid.methods, {
    addToolbarItem: function (jq, items) {
        return jq.each(function () {
            var toolbar = $(this).parent().prev("div.datagrid-toolbar");
            for (var i = 0; i < items.length; i++) {
                var item = items[i];
                if (item === "-") {
                    toolbar.append('<div class="datagrid-btn-separator"></div>');
                } else {
                    var btn = $("<a href=\"javascript:void(0)\"></a>");
                    btn[0].onclick = eval(item.handler || function () { });
                    btn.appendTo(toolbar).linkbutton($.extend({}, item, { plain: true }));
                    //btn.css("float", "left").appendTo(toolbar).linkbutton($.extend({}, item, { plain: true }));
                }
            }
            toolbar = null;
        });
    },
    removeToolbarItem: function (jq, param) {
        return jq.each(function () {
            var btns = $(this).parent().prev("div.datagrid-toolbar").children("a");
            var cbtn = null;
            if (typeof param == "number") {
                cbtn = btns.eq(param);
            } else if (typeof param == "string") {
                var text = null;
                btns.each(function () {
                    text = $(this).data().linkbutton.options.text;
                    if (text == param) {
                        cbtn = $(this);
                        text = null;
                        return;
                    }
                });
            }
            if (cbtn) {
                var prev = cbtn.prev()[0];
                var next = cbtn.next()[0];
                if (prev && next && prev.nodeName == "DIV" && prev.nodeName == next.nodeName) {
                    $(prev).remove();
                } else if (next && next.nodeName == "DIV") {
                    $(next).remove();
                } else if (prev && prev.nodeName == "DIV") {
                    $(prev).remove();
                }
                cbtn.remove();
                cbtn = null;
            }
        });
    }
});
//用法:
//$('#tt').datagrid("addToolbarItem",[{"text":"xxx"},"-",{"text":"xxxsss","iconCls":"icon-ok"}]);

最终得到时授权的操作工具栏,如下图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

如上图员工拥有对文档进行查询,添加,编辑和删除的授权操作,但是ajax发起的请求是可以伪造数据的,这就要在服务端再次对员工的授权进行验证, 此时利用AOP方式进行验证,也就是在进入真正的业务方法之前先进行授权验证,若没有权限则以抛出异常的方式终止后续操作

新建 DocCallHandler.cs, DocCallHandlerAttribute.cs和DocCallHandlerProperty.cs

/// <summary>
    /// 文档的web请求AOP
    /// </summary>
    public class DocCallHandler : CallHandlerBase
    {
        public DocCallHandler(IMessageSink nextSink)
            : base(nextSink)
        {
        }

        protected override void AddAllBeforeAOPHandles()
        {
            AddBeforeAOPHandle("ProcessRequest".ToUpper(), new BeforeAOPHandle(Before_Monitor));
        }
        protected override void AddAllAfterAOPHandles()
        {
            AddAfterAOPHandle("ProcessRequest".ToUpper(), new AfterAOPHandle(After_Monitor));
        }

        /// <summary>
        /// 在业务处理之前调用
        /// </summary>
        /// <param name="callMsg"></param>
        private void Before_Monitor(IMethodCallMessage callMsg)
        {
            if (null != callMsg)
            {
                HttpContext context = callMsg.Args[0] as HttpContext;
                string action = context.Request.Params["Action"];
                if (StringTools.MatchesStringIgnoreCase(action, "QueryDocsByDirId") || StringTools.MatchesStringIgnoreCase(action, "QueryDocsByName")
                    || StringTools.MatchesStringIgnoreCase(action, "QueryDocs") || StringTools.MatchesStringIgnoreCase(action, "QueryDocById")
                    || StringTools.MatchesStringIgnoreCase(action, "Download"))
                {
                    IsEnable(AppAction.IsEnableDocumentBrowse);
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "AddDoc"))
                {
                    IsEnable(AppAction.IsEnableDocumentAdd);
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "UpdateDoc"))
                {
                    IsEnable(AppAction.IsEnableDocumentUpdate);
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "DeleteDoc"))
                {
                    IsEnable(AppAction.IsEnableDocumentDelete);
                }
            }
        }

        /// <summary>
        /// 在业务处理之后调用
        /// </summary>
        /// <param name="replyMsg"></param>
        private void After_Monitor(IMethodReturnMessage replyMsg)
        {
            if (null != replyMsg)
            {
                HttpContext context = replyMsg.Args[0] as HttpContext;
                string action = context.Request.Params["Action"];
                if (StringTools.MatchesStringIgnoreCase(action, "Download"))
                {
                    int id = RequestParamHandler.GetIntParam(context.Request, "Id");
                    SaveOperatLog("下载文档", "Id=" + id);
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "AddDoc"))
                {
                    DocInfo doc = RequestParamHandler.GetParam<DocInfo>(context.Request, "Doc");
                    SaveOperatLog("添加文档", doc.ToString());
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "UpdateDoc"))
                {
                    DocInfo doc = RequestParamHandler.GetParam<DocInfo>(context.Request, "Doc");
                    SaveOperatLog("更新文档", doc.ToString());
                }
                else if (StringTools.MatchesStringIgnoreCase(action, "DeleteDoc"))
                {
                    int id = RequestParamHandler.GetIntParam(context.Request, "Id");
                    SaveOperatLog("删除文档", "Id=" + id);
                }
            }
        }
    }

    [AttributeUsage(AttributeTargets.Class)]
    public class DocCallHandlerAttribute : AOPAttribute
    {
        protected override AOPProperty GetAOPProperty()
        {
            return new DocCallHandlerProperty();
        }
    }

    public class DocCallHandlerProperty : AOPProperty
    {
        protected override IMessageSink CreateSink(IMessageSink nextSink)
        {
            return new DocCallHandler(nextSink);
        }

        protected override string GetName()
        {
            return "";
        }
    }

并且在DocHandler.ashx.cs加上属性[DocCallHandler],如下

    /// <summary>
    /// 文档--web处理入口
    /// </summary>
    [DocCallHandler]
    public class DocHandler : HandlerBase, IHttpHandler, System.Web.SessionState.IRequiresSessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string response = string.Empty;
            if (MatchesAction(context.Request.Params["Action"], "QueryDocsByDirId"))
            {

如员工添加文档时,

    else if (StringTools.MatchesStringIgnoreCase(action, "AddDoc"))
    {
        IsEnable(AppAction.IsEnableDocumentAdd);
    }

判断是否授权

       /// <summary>
        /// 判断是否授权
        /// </summary>
        /// <param name="validate"></param>
        protected void IsEnable(Validate validate)
        {
            FormsPrincipal<UserPrincipal> user = AuthController.GetUser();
            if (!validate(user.UserData.Permissions))
            {
                throw new NotPermissionException("");//抛出未授权异常
            }

若未授权该员工添加文档,则抛出未授权异常, Global.asax接收该异常

        /// <summary>
        /// 应用程序异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Application_Error(object sender, EventArgs e)
        {
            Exception objException = Server.GetLastError().GetBaseException();
            if (objException is NotPermissionException)
            {
                HttpContext.Current.Response.Write("{\"success\":false, \"msg\":\"无权限的操作.\"}");
            }
            else if (objException is NotLoginException)
            {
                HttpContext.Current.Response.Write("{\"success\":false, \"msg\":\"用户未登录.\"}");
            }
            else
            {
                HttpContext.Current.Response.Write("{\"success\":false, \"msg\":\"系统错误.\"}");
            }
            LogError();
            Server.ClearError();
        }

再以jsono数据格式返回响应结果,javascript再显示操作结果,如不图
ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统

代码下载1

代码下载2