Asp.net mvc 4 为什么MvcSiteMap v4中的HasChildNodes会为每个未经授权的节点触发HandleUnauthorizedRequest?

Asp.net mvc 4 为什么MvcSiteMap v4中的HasChildNodes会为每个未经授权的节点触发HandleUnauthorizedRequest?,asp.net-mvc-4,mvcsitemapprovider,Asp.net Mvc 4,Mvcsitemapprovider,我正在从MvcSiteMap的v3升级到v4,它似乎只是使用属性Html.MvcSiteMap().SiteMap.CurrentNode.HasChildNodes为列表中的每个未授权子节点触发HandleUnauthorizedRequest中的AuthorizeAttribute 为什么会这样?我希望HandleUnauthorizedRequest能够为单独的http请求触发,而不仅仅是询问节点是否存在 区分“真正的”未经授权http请求和简单检查未经授权的站点地图节点的最佳方法是什么?

我正在从MvcSiteMap的v3升级到v4,它似乎只是使用属性
Html.MvcSiteMap().SiteMap.CurrentNode.HasChildNodes
为列表中的每个未授权子节点触发
HandleUnauthorizedRequest
中的
AuthorizeAttribute

  • 为什么会这样?我希望HandleUnauthorizedRequest能够为单独的http请求触发,而不仅仅是询问节点是否存在

  • 区分“真正的”未经授权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);
        }
    }
    

  • 只有在授权检查失败的情况下,MVC authorizedRequest属性才会调用HandleUnauthorizedRequest。它仅用于设置请求的处理程序,实际上不用于检查用户是否被授权。也就是说,MvcSiteMapProvider不直接调用HandleUnauthorizedRequest,而是调用授权

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

    无论如何,为了回答您的问题,在v3和v4的早期版本中,MvcSiteMapProvider使用Reflection.Emit动态生成一个类,该类继承自AuthorizeAttribute或AuthorizeAttribute的任何子类,如中所述。该子类向AuthorizeCore方法添加了公共访问权限,因此MvcSiteMapProvider可以调用该方法。但是,这种方法存在性能问题,并且不能用于AuthorizeAttribute的密封重载

    从那时起,它已经演变为使用authorization属性的唯一公共成员—OnAuthorization—进行检查。上述文章的作者在其断言中犯了一个错误,即Reflection.Emit是唯一可以执行此操作的方法,因为他没有考虑使用覆盖输出缓存成员的HttpContext.Response子类。我们妥协使用HandleUnauthorizedAttribute的结果(将filterContext.result属性设置为非空值)作为确定安全检查是否有效的方法


    不幸的是,由于AuthorizeAttribute仅设计用于当前页面的请求上下文中,因此没有一种方法可以使解决方案在100%的时间内工作,但这是我们妥协的解决方案,因为它需要维护的代码最少,性能最好,并使用直接方法调用而不是变通方法。如果您对自定义逻辑使用重载AuthorizeCore的典型方法,它将非常有效。另一方面,如果您重载了授权或HandleUnauthorizedRequest,则需要确保filterRequest.Result属性对于unauthorized设置为非null,对于authorized设置为null。

    这非常有用。我的问题是,我正在覆盖HandleUnauthorizedRequest以拦截经过身份验证但未经授权的用户,并抛出一个异常,以使其获得授权。我不想每次调用HasChildNodes时都为每个未经授权的节点调用异常,这就是为什么我试图通过比较控制器/操作(不是为了再次授权)来过滤那些授权失败的原因。我仍然不知道如何解决这个问题。我明白你的困境。我相信,您可以通过创建的子类并在ExecuteSult方法中抛出异常来实现。与在HandleUnauthorizedRequest中抛出异常不同,您可以将其设置为正确的处理程序,并让处理程序抛出异常。MvcSiteMapProvider仅检查以确保filterContext.Result中设置了值,但它实际上并不像MVC那样执行处理程序。请参阅示例。在HttpStatusCodeResult的子类中引发异常非常有效。如果我有足够的代表,我会把两个答案都投上一票:)