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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值