为什么MvcSiteMap v4中的HasChildNodes会触发每个未授权节点的HandleUnauthorizedRequest?

时间:2014-05-02 13:28:54

标签: asp.net-mvc-4 mvcsitemapprovider

我正在从v3升级到MvcSiteMap的v4,似乎只是使用属性Html.MvcSiteMap().SiteMap.CurrentNode.HasChildNodes触发HandleUnauthorizedRequestAuthorizeAttribute对列表中每个未经协作的子节点的命中。

  1. 为什么会发生这种情况?我希望HandleUnauthorizedRequest能够被单独的http请求触发,而不仅仅是询问节点是否存在。

  2. 区分“真正的”未经授权的http请求和简单地检查未经授权的站点地图节点的最佳方法是什么?到目前为止,我最好的猜测是检查控制器和动作是否匹配,但似乎有点不必要:

    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            var httpRouteData = ((MvcHandler)filterContext.HttpContext.CurrentHandler).RequestContext.RouteData;
            var filterRouteData = filterContext.RequestContext.RouteData;
    
            var isHttpRequestUnauth = (httpRouteData.Values["Controller"] == filterRouteData.Values["Controller"] &&
                httpRouteData.Values["Action"] == filterRouteData.Values["Action"]);
    
            if (isHttpRequestUnauth)
                throw new System.Web.HttpException(403, string.Format("Access denied for path '{0}'. ", filterContext.HttpContext.Request.RawUrl));
            else
                base.HandleUnauthorizedRequest(filterContext);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
    

1 个答案:

答案 0 :(得分:1)

HandleUnauthorizedRequest仅在授权检查失败的情况下由MVC AuthorizeAttribute调用。它仅用于设置请求的处理程序,而不是实际上用于检查用户是否被授权。也就是说,MvcSiteMapProvider不直接调用HandleUnauthorizedRequest - 它调用OnAuthorization。

default implementation of AuthorizeAttribute.OnAuthorization已经进行了检查,所以我不确定你希望通过在HandleUnauthorizedRequest中再次比较控制器和操作来实现什么,因为未经授权的用户无法到达该路径,除非你也覆盖了OnAuthorization的实现(或者你完全依赖输出缓存。

无论如何,要回答你的问题,在v3和v4的早期版本中,MvcSiteMapProvider使用Reflection.Emit生成一个动态类,它继承自AuthorizeAttribute或AuthorizeAttribute的任何子类,如this post中所述。子类添加了对AuthorizeCore方法的公共访问,因此可以通过MvcSiteMapProvider调用它。但是,该方法存在性能问题,也无法与AuthorizeAttribute的密封重载一起使用。

从那时起,它已经发展到使用AuthorizeAttribute的唯一公共成员 - OnAuthorization - 来进行检查。上述帖子的作者在他的断言中犯了一个错误,即Reflection.Emit是唯一可行的方法,因为他没有考虑使用覆盖输出缓存成员的HttpContext.Response的子类。我们在使用HandleUnauthorizedAttribute的结果(将filterContext.Result属性设置为非null值)时作为确定安全检查是否有效的方法而妥协。

不幸的是,没有办法让解决方案100%的工作时间,因为AuthorizeAttribute只是在当前页面请求的上下文中使用,但这是我们妥协的解决方案,因为它需要最少量的代码来维护,执行最佳,并使用直接方法调用而不是变通方法。如果您使用典型的方法将AuthorizeCore重载为自定义逻辑,它将完美地工作。另一方面,如果重载OnAuthorization或HandleUnauthorizedRequest,则需要确保filterRequest.Result属性对于未授权设置为非null,对于授权设置为null。