ASP.NET经典权限解决方案,适用于OA、CRM、ERP、HR等应用系统
经典权限解决方案
1.权限简介
一般的管理系统都需要对用户的操作进行一定的限制,有的用户可以有许多操作,有的则有少量的操作.这样就需要一个授权机制,基于角色的授权机制描述了某个角色拥有一定数量的操作授权,属于该角色的用户则也就拥有了该角色的权限,且若用户属于多个角色则其拥有多个角色权限的集合.
我们的权限精确到按钮级别,如共享文档管理,管理可以查询、上传文档、下载文档、删除文档等操作,而一般的用户只需要查询和下载文档就可以了,
这时候我们的权限管理就发挥了作用, 下面让我们一步步开始实现!
我们使用ASP.NET结合jQuery、EasyUI实现一个精典的权限管理机制
2.数据模型设计
数据模型包括:员工表,角色表,员工与角色关系表和角色权限表
员工表: 员工登录到系统,如下图
角色表:授权权限的集合对象,如下图
角色表与员工关系表:如下图
角色权限表:如下图
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数据表格组件,效果如下图
勾选复选框就表示为该角色授权其他的操作
权限目录树的初始化,如下(在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
保存结果如下图 :
5.新建员工,并为员工分配角色,如下图:
6.员工登录: 登录后获取员工基本信息和授权信息等保存在Cookie中,以后员工的每次操作都从Cookie中获取授权信息并以AOP方式进行权限验证,没有授权的操作以抛出权限异常的方式终止操作,以保护数据的安全
登录:
登录请求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.以文档管理为例讲解员工的授权,页面如下图
新建文档管理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"}]);
最终得到时授权的操作工具栏,如下图
如上图员工拥有对文档进行查询,添加,编辑和删除的授权操作,但是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再显示操作结果,如不图