如果想要記錄ajax的請求和輸出信息、內部發生異常記錄日志、需要登錄認證、需要權限判斷;那mvc的各種filter可以幫助你實現你想要的。Mvc框架支持5種不同類型的過濾器;我會按照執行順序進行簡單的demo,再簡單的代碼分享,萬一對一個人有益,也是值的。
1.通過實現IAuthenticationFilter來進行登錄認證,如果認證通過繼續后續的權限授權等操作;如果認證沒有通過跳轉登錄頁面;代碼如下:
public class MvcAuthenticationFilter : FilterAttribute, IAuthenticationFilter { /// <summary> /// 是否需要認證 /// </summary> public bool IsNeedAuthentication { get; set; } /// <summary> /// 對請求進行身份驗證 /// </summary> /// <param name="filterContext"></param> public void OnAuthentication(AuthenticationContext filterContext) { bool flag = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true); if (flag) { return; } if (IsNeedAuthentication) { IPrincipal user; if (this.IsAuthenticated(filterContext, out user)) { filterContext.Principal = user; } else { this.UnauthenticatedRequest(filterContext); } } } protected bool IsAuthenticated(AuthenticationContext filterContext, out IPrincipal user) { user = filterContext.HttpContext.User; var cc = filterContext.Controller.ControllerContext.Controller as BaseController; if (cc != null && cc.CurrentAdminInfo != null) { IIdentity identity = user.Identity; user = new GenericPrincipal(identity, new[] { "root", "noroot" }); //這里根據實際情況獲取用戶的角色 return true; } return false; } protected void UnauthenticatedRequest(AuthenticationContext filterContext) { string returnUrl = filterContext.HttpContext.Request.Url.AbsolutePath; string redirectUrl = string.Format("?ReturnUrl={0}", returnUrl); string loginUrl = FormsAuthentication.LoginUrl + redirectUrl; filterContext.HttpContext.Response.Redirect(loginUrl, true); } public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) { } }
2.每個管理后台都少不了權限判斷的需求;你可以使用[Authorize(Roles = "r1,r2")] 默認實現進行硬編碼,對於用戶的權限和角色經常變動的話,或者你需要靈活的處理就需要自定義Authorize,咱們先看下Authorize源代碼實現你就會明白
他的實現原理,先判斷是否有匿名訪問標簽,然后利用AuthorizeCore 授權檢查,如果未授權利用HandleUnauthorizedRequest 放回401,跳轉到登錄頁面;很明顯授權不通過跳轉登錄頁面不是太合適;另一種實現方式 自定義Authorize 代碼如下:
public new string[] Roles { get; set; } protected override bool AuthorizeCore(HttpContextBase httpContext) { //由原來指定的roles 替換成動態讀取的。 //跟登錄用戶的roles進行比較。 if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (!httpContext.User.Identity.IsAuthenticated) { return false; } if (Roles == null) { return true; } if (Roles.Length == 0) { return true; } if (Roles.Any(new Func<string, bool>(httpContext.User.IsInRole))) { return true; } httpContext.Response.StatusCode = 403; return false; } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.Result = new HttpUnauthorizedResult(); } public override void OnAuthorization(AuthorizationContext filterContext) { bool flag = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true); if (flag) { return; } string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string actionName = filterContext.ActionDescriptor.ActionName; string roles = string.Join(",", GetRoles(actionName, controllerName)); if (!string.IsNullOrWhiteSpace(roles)) { this.Roles = roles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); } base.OnAuthorization(filterContext); if (filterContext.HttpContext.Response.StatusCode == 403) { //跳轉未授權頁面 filterContext.Result = new RedirectResult("/Other/Noright"); } }
3.動作過濾器記錄一些ajax的輸入輸出數據,方便排查問題;代碼有注釋也比較簡單直接貼代碼了
public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { var httpContext = filterContext.HttpContext; //輸入參數 var req = new JavaScriptSerializer().Serialize(HttpContext.Current.Request.Form.AllKeys.ToDictionary(k => k, k => HttpContext.Current.Request.Form[k])); var code = httpContext.Request.GetHashCode(); var controllerName = filterContext.RouteData.Values["controller"] as string; var actionName = filterContext.RouteData.Values["action"] as string; var postUrl = controllerName + "/" + actionName; LogHelper.WriteDebug( string.Format("RequestUrl:{0};HashCode:{1}</br>RequestParam{2}", postUrl, code, req)); } } public override void OnActionExecuted(ActionExecutedContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { //輸出參數 var jsonR = filterContext.Result as JsonResult; var res = new JavaScriptSerializer().Serialize(jsonR); LogHelper.WriteDebug(string.Format("OnActionExecuted---返回值:{0}", res)); } }
4.最后是發生異常的處理,mvc默認實現HandleErrorAttribute,但是也不夠靈活,查看源代碼
我們定義之后的代碼
public override void OnException(ExceptionContext filterContext) { string errCode = ""; string errMsg = ""; //自定義錯誤 if (filterContext.Exception is ClException) { } else { errMsg = "未知錯誤"; LogHelper.WriteError(filterContext.Exception.Message); } //如果是ajax請求 if (filterContext.HttpContext.Request.IsAjaxRequest()) { var result = new ExceptionResponse { ErrMsg = errMsg, }; filterContext.Result = new JsonResult() { Data = result }; }//500服務器內部錯誤 else { filterContext.Result = new ViewResult() { ViewName = "/Views/Other/Seerro.cshtml" }; } filterContext.ExceptionHandled = true;//阻止golbal里的錯誤執行 filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.StatusCode = 500; filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;//禁用 IIS 自定義錯誤 }
看下彈出的錯誤效果