MVC3权限设计详解
1.设计过滤器:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class OperationCheckAttribute : ActionFilterAttribute { /// <summary> /// 是否异步触发的验证。 /// 如果前台用ajax执行Action,IsAsync=true;否则IsAsync=false。 /// 这样做的目的是当没有权限时给出不同的提示方式. /// (直接点Url打开页面时没有权限就跳转到没有权限提示页面, /// ajax点击按钮时就以弹出框形式提示) /// /// </summary> public bool IsAsync { get; set; } /// <summary> /// 操作代码1101,1102,1103 /// </summary> public string OpCode { get; set; } /// <summary> /// 模块操作代码 /// </summary> public string OpModel { get; set; } /// <summary> /// 标记Key /// </summary> public string PmKey { get; set; } /// <summary> /// 标记Key /// </summary> public string PmValue { get; set; } /// <summary> /// 运算类型= true 或 != false /// </summary> public bool IsNull { get; set; } private bool actionCheck = false; /// <summary> /// Action方法执行前执行 /// </summary> /// <param name="filterContext"></param> public override void OnActionExecuting(ActionExecutingContext filterContext) { if (!string.IsNullOrEmpty(PmKey)) { //PmKey 不为空 PmValue 为空时,确定一个Action方法有多个权限判断 string value =null; if(filterContext.ActionParameters[PmKey]!=null) value = Convert.ToString(filterContext.ActionParameters[PmKey]); if (PmValue == null) { if (string.IsNullOrWhiteSpace(value) && IsNull) { actionCheck = true; } else if (!string.IsNullOrWhiteSpace(value) && !IsNull) { actionCheck = true; } } //PmKey 不为空 PmValue 不为空时,确定一个Action方法有多个权限判断 else if (!value.Equals(null)) { if (value.ToLower() == PmValue.ToLower()) actionCheck = true; } } else if (!string.IsNullOrEmpty(OpCode)) { actionCheck = true; } if (actionCheck) { bool isViewPage = true; if (filterContext.HttpContext.Request.HttpMethod.ToUpper() == "POST") { isViewPage = false; } UserManageBusiness userManage = new UserManageBusiness(); TSysUser model = HttpContext.Current.Session["_sso_elab_user_"] as TSysUser; if (model != null) { bool isOk = userManage.AuthCheck(model.UserID, OpCode);//权限验证 if (!isOk) { if (isViewPage) filterContext.Result = new RedirectResult("~/Home/PurviewCheck"); else filterContext.Result = new ContentResult { Content = "0" };//为前端是用ajax提交,返回是JsonResult的提供无权限处理 } } else { filterContext.Result = new RedirectResult("~/Home/PurviewCheck"); } } base.OnActionExecuting(filterContext); } /// <summary> /// Action方法执行后返回前执行 /// 处理界面按钮显示 /// </summary> /// <param name="filterContext"></param> public override void OnResultExecuting(ResultExecutingContext filterContext) { actionCheck = false; UserManageBusiness userManage = new UserManageBusiness(); OperationBusiness operationBusiness = new OperationBusiness(); string sAction = filterContext.RouteData.Values["action"].ToString(); TSysUser model = HttpContext.Current.Session["_sso_elab_user_"] as TSysUser; if (model != null) { if (!string.IsNullOrEmpty(OpModel)) { TSysRoleUserMapping mapping = userManage.FindRoleUserMap(model.UserID); DataTable dt = operationBusiness.FindListMarkedByRole(mapping.RoleID); DataRow[] dr = null; if (OpModel == "00") { dr = dt.Select(""); } else { dr = dt.Select("OpModel=" + OpModel); } foreach (DataRow item in dr) { //审批页面特殊处理:只能让域配置的区域管理员课件 if (item["OpCode"].ToString()=="1105") { filterContext.Controller.ViewData.Add("Limited" + item["OpCode"], userManage.ApproveLimited(model.UserID, model.DomainID) ? "" : "display:none"); } else { filterContext.Controller.ViewData.Add("Limited" + item["OpCode"], bool.Parse(item["RoleMark"].ToString()) || userManage.BeyondLimited(model.UserID, mapping.RoleID) ? "" : "display:none"); } } } } else { filterContext.Result = new RedirectResult("~/Home/PurviewCheck"); } } }
2.后台方法添加过滤器:(含新增和编辑是同一页面这种复杂的处理)
[OperationCheck(OpCode = "0401", PmKey = "isCreate", PmValue = "true")] [OperationCheck(OpCode = "0402", PmKey = "isCreate", PmValue = "false")] public ActionResult AddDomain(Guid? domainId, string isCreate)
{
//...
return View(orgDomain);
}
[HttpPost] [OperationCheck(OpCode = "0401", PmKey = "isCreate", PmValue = "true")] [OperationCheck(OpCode = "0402", PmKey = "isCreate", PmValue = "false")] public JsonResult Add(TSysDomain domain, string isCreate)
{
//...
return Json(new {Id=...});
}
3.前台连接页面事件,过滤器返回的是页面,前端不用处理
$("#btnShowNew").click(function () { var row = $('#DomainTable').treegrid('getSelections'); if (row != null && row.length > 0) { var domainID = ""; if (row.length > 1) { alert(Language_Domain_EditOnlyCanSelectOneToCreateWarning); } else { domainID = row[0].DomainID; //var css = row[0].CSSFileName; if (row[0].Enable == false) { alert("该区域已冻结,不能在此域下新增!"); } else { var url = '@Url.Action("AddDomain", "Domain")' + "?isCreate=true" + "&domainId=" + domainID; location.href = url; } //window.open(url);//这种方式有问题 } } else { var url = '@Url.Action("AddDomain", "Domain")' + "?isCreate=true"; location.href = url; } })
功能按钮显示隐藏:
<div class="classdetail_btn_box01" style="@ViewData["Limited0401"]"> <div class="classdetail_btn_box0101"> @*<a href="@Url.Action("AddDomain", "Domain")"><span id="btnShowNew" style="@ViewData["Limited0401"]" class="classdetail_btn_box0102 domains_btn_box"></span></a>*@ <span id="btnShowNew" class="classdetail_btn_box0102 domains_btn_box"></span> </div> </div>
4.在用Ajax提交事件中,要自行处理经过滤器过滤后的结果,
$.ajax({ url: '@Url.Action("Add", "Domain")' + "?isCreate=" + '@Session["isCreate"]', type: "POST", async: false, //代表同步 data: { xDomainId: $("#DomainID").val(), xParentId: $("#ParentID").val(), xParentName: encodeURIComponent($("#ParentDomainName").val()), xDomainName: encodeURIComponent($("#DomainName").val()),
。。。。。 }, success: function (result) { if (result == "0") { window.location.href = '@Url.Content("~/Home/PurviewCheck")' } else { if (result.DomainID != '@Guid.Empty') { window.location.href = '@Url.Content("~/Domain/AddDomain")' + "?domainId=" + result.DomainID + "&isCreate=false"; } } }, error: function (result) { alert(result.message); } });
因为在Ajax中,执行过滤器后最终会跑到我们的success代码中,
过滤器执行后的结果就是result,此时result是html页面代码(含js代码),这个js代码不会自己执行的,要自己去处理。
即使把过滤器中filterContext.Result = new ContentResult { Content = ""<script type='text/javascript'>alert('权限验证不通过!');history.go(-1);</script>"" };它也不会去执行,Ajax这种提交不同于简单的页面URL连接,不管有没用进后台,如果没有权限,只要语法没错,它依然会执行success函数.
==>上面这段经同事验证是不正确的,用JS可以实现
不用走Ajax Success函数后面的代码(如果验证是没有权限的话)
在公用的JS重加入如下代码:
/*Ajax没有权限操作,跳转*/ $(function () { $("body").ajaxComplete(function (event, request, settings) { if (request.responseText == "NotAuthorized") { window.location.href = window.parent.document.URL + "/Home/PurviewCheck"; } }); })
,所用上面的Success函数可以修改如下:
success: function (result) { if (result.DomainID.length == 32) { if (result.DomainID != '@Guid.Empty') { window.location.href = '@Url.Content("~/Domain/AddDomain")' + "?domainId=" + result.DomainID + "&isCreate=false"; } } }, error: function (result) { alert(result.responseText); }
Fitler如下改:
filterContext.Result = new ContentResult { Content = "NotAuthorized" };
经验证,这样也是不对的,第一次可以 ,多试几次就多往下执行了。
于是,想到了ajax的几个事件的执行循序,
(参考园子里张子秋的博客:http://www.cnblogs.com/zhangziqiu/archive/2009/05/08/jQuery-Learn-6.html)
$("body").ajaxError(function (event, request, settings, errorThrown) (异常时执行)
$("body").ajaxStart(function (event, request, settings, errorThrown)(AJAX 请求开始时执行函数)
$("body").ajaxSendfunction (event, request, settings, errorThrown)(AJAX 请求发送前执行函数)
$("body").ajaxSucess(function (event, request, settings, errorThrown)(AJAX 请求成功时执行函数)
$("body").ajaxCompleted(function (event, request, settings, errorThrown)(AJAX 请求完成时执行函数)
$("body").ajaxStop(function (event, request, settings, errorThrown)(AJAX 请求结束时执行函数)
结合我们的过滤器,执行循序如下:
ajax提交->
ajaxStart,
ajaxSend,
Fitler
ajaxSuccess
ajaxCompleted
ajaxStop
-->重新回到ajax 提交的success函数
如此一来的话,还是会执行success函数以下的代码,过滤器没有起到拦截的作用。
想到过滤器中设置错误代码,request.status,参考园子里:http://www.cnblogs.com/wintersun/archive/2011/12/18/2291800.html
JQuery的全局AjaxError配置,可参考官方 $("#errorh3info").ajaxError(function (event, request, settings) { $(this).append("<li>settings.url:" + settings.url + "</li>"); $(this).append("<li>request.status:" + request.status + "</li>"); $(this).append("<li>request.statusText:" + request.statusText + "</li>"); //request.responseText if (request.responseText != "") { var jsonValue = jQuery.parseJSON(request.responseText); $(this).append("<li>ErrorMessage:" + jsonValue.ErrorMessage + "</li>"); } }); 给button增加一个Post请求: $('#inputajax1').click(function () { $.post('/Home/YouKnow/' , { id: 1 } , function (data) { $('div#right-box.data').html(data); }); }); 这时View上将显示, 我们将看到ErrorMessage是JSON对象的属性: settings.url:/Home/YouKnow/ request.status:500 request.statusText:error ErrorMessage:Value cannot be null. Parameter name: YouKnow method: fc should not be null
在过滤器设置500错误代码,进入ajaxError,如果真能进来,我就可以这样:
$("body").ajaxError(function (event, request, settings, errorThrown) { alert("ajaxError"); if (request.responseText.indexOf("*|") > 0 && request.status == 500) { window.location.href = window.parent.document.URL + "/Home/PurviewCheck"; return; } });
这样便实现拦截了,
可以有时,你设置了错误代码,它也不进入ajaxError,
郁闷中,求解!
阿里云: www.aliyun.com
华赐软件: www.huacisoft.com
C#开源社区: www.opencsharp.net
清泓美肤苑: 清泓美肤苑
bootstrap权限管理系统: Asp.Net Mvc3 bootstrap权限管理系统