首页 > 学院 > 开发设计 > 正文

重写Authorize过滤器导致的登录已经失效,但却没有跳转到登录页问题的解决

2019-11-09 20:47:15
字体:
来源:转载
供稿:网友

最近在调试一个新做的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 OnAuthorization
kong: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
方法的开始。问题也得以解决


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表