启用安全调整后,如何提高MVC SiteMap Provider的响应能力

时间:2019-04-11 16:19:26

标签: c# asp.net-mvc mvcsitemapprovider

我刚刚注意到,在ASP.NET MVC 5.x站点中使用MVC Sitemap启用安全性调整会大大降低Web请求的速度。

我从documentation那里了解到,打开security trimming时,MVC站点地​​图提供程序在站点地图中的每个控制器的实例上创建,以检查该节点对于当前节点是否可见用户(根据网络请求)。

我还read将每个Web请求都缓存,以将影响降到最低。

当我们的Io​​C框架将大多数控制器的依赖项管理为singleton时,这种行为通常不会引起我们的注意(这意味着获得控制器的实例非常快)。

最近,我们的要求发生了变化,并且大多数依赖项都具有每个Web请求的生活方式,这对MVC Sitemap提供商的性能产生了巨大的负面影响: 在我们的开发机上,mvc网站地图需要花费5秒钟(!)来完成其工作(实例化所有构造函数)。

启用安全调整后,可以采取任何措施来加快速度吗?

注意:

也许值得一提的是,我们遵循在构造函数应用程序中不执行任何操作的最佳做​​法,即将参数分配给实例变量或属性,以避免进一步降低速度。

我们还坚持使用Microsoft提供的默认Authorize属性。

2 个答案:

答案 0 :(得分:0)

这是我最终实现的解决方案:

  1. 关闭安全设置关闭
  2. 向MVC站点地​​图(在XML文件中)节点添加了一个新属性restrict-to-role,该节点与用[Authorize(Roles="Role1,Role2")]属性修饰的控制器动作匹配。
  3. 添加了新的可见性提供程序,该提供程序可检查当前节点的属性是否具有restrict-to-roles属性。如果有值,则调用ASP.NET身份的IsInRole方法来检查当前用户是否可以看到该节点。
public class RolesInXmlFileSecurityTrimmingVisibilityProvider : SiteMapNodeVisibilityProviderBase
{
    public override bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
    {
        var isVisible = true;

        if (node.Attributes.ContainsKey("restrict-to-roles"))
        {
            var roles = Convert.ToString(node.Attributes["restrict-to-roles"]);

            if (!string.IsNullOrEmpty(roles))
            {
                 // Your implemenation may vary
                 isVisible = IsInRole(roles);
            }
        }

        return isVisible;
    }
}

优势:

这非常快,您无需实例化所有控制器来寻找[Authorize]属性。

缺点:

您必须在控制器中MVC restric-to-roles顶部的MVC站点地​​图文件中手动维护[Authorize]属性。

答案 1 :(得分:0)

@bounav,谢谢,谢谢,谢谢!虽然不是一个理想的解决方案,但它确实有效,而且节省的时间/处理过程确实会对我的客户产生巨大的影响/差异。

虽然基于上面的解决方案,我实现的代码差异很大。我会在这里发布关键部分,希望对其他人有所帮助。

变更摘要 此实现使用线程原理 (IPrincipal)。有一些调整可以处理多个角色以及使用 [Authorize] 属性而没有任何特定角色的控制器(用户只需要经过身份验证)。我将属性的名称从“restrict-to-roles”更改为“Roles”。这允许我简单地将每个控制器的 [Authorize] 属性中的值复制/粘贴到 Mvc.sitemap XML 文件中。例如这个控制器属性:

[Authorize(Roles = "YourSecurityRole")]

在 Mvc.sitemap XML 文件中变成这个:

<mvcSiteMapNode title="Your Title" controller="Yourcontroller" Roles = "YourSecurityRole" action="YourControllerAction" key="YourNodeKey">

这是相关的类:

public class RolesInXmlFileSecurityTrimmingVisibilityProvider : SiteMapNodeVisibilityProviderBase
{
    public override bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
    {
        // If the sitemap node does not contain the 'roles' attribute, simply return true.
        if (!node.Attributes.ContainsKey("Roles"))
        {
            return true;
        }

        // When the sitemap node contains the 'roles' attribute, the user must at least be authenticated for the node to be visible.
        var currentUser = Thread.CurrentPrincipal;
        if (currentUser == null || currentUser.Identity == null || currentUser.Identity.IsAuthenticated == false)
        {
            return false;
        }

        var strRoles = Convert.ToString(node.Attributes["Roles"]);
        if (string.IsNullOrWhiteSpace(strRoles))
        {
            return true; // Use an empty Roles="" attribute/value for controllers with only the basic [Authorize] attribute
        }
        else
        {
            var arrRoles = strRoles.Split(',');
            foreach (var role in arrRoles)
            {
                if (currentUser.IsInRole(role))
                {
                    return true; // The authenticated user matches at least one of the roles required for visibility.
                }
            }
        }

        return false; // The authenticated user did not match any of the roles required for visibility.
    }
}

由于我们使用了 Ninject DI,我还想提及另外三个值得注意的技术细节。

  1. 使用 NinjectModule 作为基类的“MvcSiteMapProviderModule”是我禁用安全修整的地方。重写的 Load() 方法,摘录:

    bool securityTrimmingEnabled = false;

    // Configure the builder sets .Kernel.Bind<ISiteMapBuilderSet>().To<SiteMapBuilderSet>().Named("siteMapBuilderSet1").WithConstructorArgument("instanceName", "default").WithConstructorArgument("securityTrimmingEnabled", securityTrimmingEnabled)...<removed for brevity>

  2. 用于“ISiteMapNodeVisibilityProviderStrategy”的类必须按如下方式换出:

    this.Kernel.Bind<ISiteMapNodeVisibilityProviderStrategy>().To<SiteMapNodeVisibilityProviderStrategy>() .WithConstructorArgument("defaultProviderName", "YourNamespace.RolesInXmlFileSecurityTrimmingVisibilityProvider, YourAssemblyName");

  3. 除非您希望 URL 中出现额外的“Roles”属性,否则您必须这样配置“attributesToIgnore”值:

    // Prepare for our node providers this.Kernel.Bind<IXmlSource>().To<FileXmlSource>().Named("XmlSource1") .WithConstructorArgument("fileName", absoluteFileName);

    this.Kernel.Bind<ISiteMapXmlReservedAttributeNameProvider>().To<SiteMapXmlReservedAttributeNameProvider>().Named("xmlBuilderReservedAttributeNameProvider").WithConstructorArgument("attributesToIgnore", new string[1] { "Roles" });

希望有所帮助!