如何创建过滤器以防止操作方法查找空对象

时间:2014-12-05 15:19:27

标签: c# asp.net asp.net-mvc

我已经创建了下面的过滤器,将我的应用程序部分的访问权限限制为仅登录的用户。但是,我的应用程序仍然抱怨在过滤器触发重定向之前尚未实例化用户对象。在操作方法有机会注意到对象为空之前,如何让用户重定向?#/ p>

上下文

为了完整起见,值得一提:

UserSession.CurrentOrDefault();

如果找到存储在当前会话中的值,则返回该对象;如果该会话不存在,则返回null。

过滤器

public class RestrictAccess : ActionFilterAttribute
{
    public UserRole RequiredRole { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var userSession = UserSession.CurrentOrDefault();
        if(userSession != null)
        {
            int userRole = Convert.ToInt32(userSession.User.Role);
            int requiredRole = Convert.ToInt32(this.RequiredRole);
            if(userRole >= requiredRole)
            {
                base.OnActionExecuting(filterContext);
                return;
            }
            else
            {
                HttpContext.Current.Response.Redirect("/");
                return;
            }
        }

        HttpContext.Current.Response.Redirect("/Session/Create");
    }
}

抱怨的示例操作方法:

[RestrictAccess]
public ActionResult Index()
{

    var userSession = UserSession.CurrentOrDefault();

    // This is the part that throws the exception. userSession.User is null here.
    // My expectation was for this to be unreachable if user is null because of the filter.
    var model = new IndexViewModel { User = userSession.User };

    return View(model);
}

2 个答案:

答案 0 :(得分:1)

您应该为此实现自己的AuthorizeAttribute

public class Authorization : AuthorizeAttribute
    {    
        public UserRole RequiredRole { get; set; }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            var userSession = UserSession.CurrentOrDefault();
            if(userSession != null)
            {
               int userRole = Convert.ToInt32(userSession.User.Role);
               int requiredRole = Convert.ToInt32(this.RequiredRole);
               if(userRole >= requiredRole)
               {

                  return true;
               }
               else
               {
                   return false;
               }
            }
            return false;
        }

        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            try
            {
                if (AuthorizeCore(filterContext.HttpContext))
                {
                    // ** IMPORTANT **
                    // Since we're performing authorization at the action level, the authorization code runs
                    // after the output caching module. In the worst case this could allow an authorized user
                    // to cause the page to be cached, then an unauthorized user would later be served the
                    // cached page. We work around this by telling proxies not to cache the sensitive page,
                    // then we hook our custom authorization code into the caching mechanism so that we have
                    // the final say on whether a page should be served from the cache.

                    HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
                    cachePolicy.SetProxyMaxAge(new TimeSpan(0));
                    cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);

                }
                else 
                { 
                   filterContext.Result = new RedirectResult("/Session/Create");

                }
            }
            catch (Exception)
            {
                filterContext.Result = new RedirectResult("/Session/Create");
            }
        }

        private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
        {
            validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
        }
}

答案 1 :(得分:0)

当您调用HttpContext.Current.Response.Redirect时,您将不在MVC架构之外,因此它不知道不运行操作方法,因此继续和错误。

相反,您应该将ActionExecutingContext filterContext的{​​{3}}设置为Result,如下所示:

public class RestrictAccess : ActionFilterAttribute
{
    public UserRole RequiredRole { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var userSession = UserSession.CurrentOrDefault();
        if(userSession != null)
        {
            int userRole = Convert.ToInt32(userSession.User.Role);
            int requiredRole = Convert.ToInt32(this.RequiredRole);
            if(userRole >= requiredRole)
            {
                base.OnActionExecuting(filterContext);
                return;
            }
            else
            {
                filterContext.Result = new RedirectResult("/");
                return;
            }
        }

        filterContext.Result = new RedirectResult("/Session/Create");
    }
}