最近在調試一個新做的MVC項目的時候發現在類別添加頁面大類列表為空,檢查發現并沒有從數據庫中讀取到類別數據。很納悶,由于這個類別列表是Ajax請求所得,審查元素,檢查相應的js文件。發覺有錯誤提示:
ReferenceError: loginVM is not defined
檢查loginVM,發覺是登錄模塊,這才發現登錄已經超時。這什么情況,登錄超時不是應該自動跳轉到登錄頁面么。沒執行?由于我這個后臺控制登錄權限驗證的是Authorize過濾器,于是進行相應檢查。
我寫的是AdminUnauthorizedReturnUrl類,繼承的是xmlAuthorizeAttribute類,代碼如下:
public class AdminUnauthorizedReturnUrl : XMLAuthorizeAttribute { PRotected override bool AuthorizeCore(HttpContextBase httpContext) { EventLog.WriteLog("child AuthorizeCore"); bool hasRole = base.AuthorizeCore(httpContext); //如果為空,則表示尚未登錄,為false if (httpContext == null) { throw new ArgumentNullException("httpContext"); } return hasRole; } public override void OnAuthorization(AuthorizationContext filterContext) { EventLog.WriteLog("child OnAuthorization"); if (filterContext.HttpContext.User == null) { return; } if (filterContext.HttpContext.User.Identity == null) { return; } string userId = filterContext.HttpContext.User.Identity.GetUserId(); EventLog.WriteLog("kong:" + userId.IsNullOrEmpty()); if (userId.IsNullOrEmpty()) { //EventLog.WriteLog("為空"); return; } using (var db = new LMIdentityDbContext()) { var user = db.Users.Find(userId); if (user == null) { //EventLog.WriteLog("為空1"); return; } string role = user.Role; //EventLog.WriteLog("role:" + role); ; //EventLog.WriteLog(user.UserName); //表示是管理員,且用戶已經被驗證 if (filterContext.HttpContext.User.Identity.IsAuthenticated && role == "admin") { bool hasRole = (this.Roles == null || this.Roles.Length == 0 || this.Roles.Any((string a) => filterContext.HttpContext.User.IsInRole(a))); //EventLog.WriteLog("" + (hasRole)); if (!hasRole) //表示沒有后臺操作的角色權限 { //表示沒有頁面的操作權限,則跳到平臺后臺首頁 filterContext.Result = new RedirectResult("/admin/home/UnAuthorize", true); return; } } } base.OnAuthorization(filterContext); } /// <summary> /// 權限跳轉類 /// </summary> /// <param name="filterContext"></param> protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); } }XMLAuthorizeAttribute類的代碼如下: public class XMLAuthorizeAttribute : AuthorizeAttribute { public new string[] Roles { get; set; } protected override bool AuthorizeCore(HttpContextBase httpContext) { EventLog.WriteLog("base AuthorizeCore"); if (httpContext == null) { throw new ArgumentNullException("HttpContext"); } return httpContext.User.Identity.IsAuthenticated && (this.Roles == null || this.Roles.Length == 0 || this.Roles.Any((string a) => httpContext.User.IsInRole(a))); } public override void OnAuthorization(AuthorizationContext filterContext) { EventLog.WriteLog("base OnAuthorization"); string text = (filterContext.RouteData.DataTokens["area"] as string) ?? ""; string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string actionName = filterContext.ActionDescriptor.ActionName; //獲取頁面的所有權限,頁面權限形式:admin,審核,財務,agent,短信 string actionRoles = GetRoles.GetActionRoles(actionName, ((text.Length > 0) ? (text + "/") : "") + controllerName); //EventLog.WriteLog(controllerName); //EventLog.WriteLog(actionName); //EventLog.WriteLog("actionRoles" + (actionRoles)); this.Roles = actionRoles.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries); base.OnAuthorization(filterContext); } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { base.HandleUnauthorizedRequest(filterContext); //if (filterContext.HttpContext.Response.StatusCode == 401) //{ // filterContext.Result = new RedirectResult("/"); //} } } 我們知道權限過濾器的執行順序為:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest ,因此我在AdminUnauthorizedReturnUrl類中的AuthorizeCore及OnAuthorization增加了中間變量輸出輸出。使用的是eventlog.writelog輸出。編譯刷新當前頁面后輸出如下:child OnAuthorizationkong:True這使我確定了在子類的OnAuthorization中由于userid為空,執行了return.但并沒有自動跳轉到AuthorizeCore中去判斷hasRole是否為真。剛開始是以為后臺頁面權限的xml文件沒配置完全造成。配置后,結果仍是如此。進行各種嘗試,均沒有解決。后來想到,難道要調整base.OnAuthorization(filterContext);的位置,因為我是把他放置到方法結尾了。于是我把其調整到方法開始的第一行,這次沒有再停留到原頁面,直接跳轉到了登錄頁面。看來真是這里的問題,之所以剛開始沒考慮到是這里的問題,是因為以前方法重寫的時候,base執行父類方法的語句,放在開始和結尾是沒分別的。為什么在這個方法中就出問題了呢。于是我反編譯了system.web.mvc中的AuthorizeAttribute類。找到了OnAuthorization得實現方法。代碼如下:public virtual void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } if (OutputCacheAttribute.IsChildActionCacheActive(filterContext)) { throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache); } bool flag = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true); if (flag) { return; } if (this.AuthorizeCore(filterContext.HttpContext)) { HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache; cache.SetProxyMaxAge(new TimeSpan(0L)); cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), null); return; } this.HandleUnauthorizedRequest(filterContext); }這里看到了這行語句:if (this.AuthorizeCore(filterContext.HttpContext)),看到這行語句我也理解了為什么執行順序是OnAutorization=>AutorizeCore,原來在這個OnAuthorization方法中調用了AuthorizeCore方法。當AuthorizeCore返回false的時候執行了this.HandleUnauthorizedRequest(filterContext),這個就是沒有權限要跳轉頁面的設置方法。來看AuthorizeAttribute類中這個方法的源碼:protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext) { filterContext.Result = new HttpUnauthorizedResult(); }執行的是這行代碼:filterContext.Result = new HttpUnauthorizedResult();而我在重寫的AdminUnauthorizedReturnUrl類及XMLAuthorizeAttribute類中均沒有做跳轉頁面的改變。因此系統默認還是執行的filterContext.Result = new HttpUnauthorizedResult();這個方法執行的是項目中Startup類中設置的默認跳轉頁面。我這里設置的是/account/login。到這里對權限過濾器的執行有了深入的理解,也明白了為什么base.OnAuthorization(filterContext);必須放置在OnAuthorization方法的開始。問題也得以解決
新聞熱點
疑難解答