启用安全修整的 MvcSiteMapNodeProvider 抛出 sql 异常

MvcSiteMapNodeProvider with security trimming enabled throws sql exception

当我 运行 我的 MVC5 EF6 MSSQL 2012 应用程序时,我收到以下异常。

我将问题追踪到配置中的一行

<add key="MvcSiteMapProvider_SecurityTrimmingEnabled" value="true" />

删除此行后,我的网站可以正常构建,但当然安全修整已关闭,所以现在我的菜单已损坏。

整个appSettings部分如下

<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="SkipApplicationAuthorizationRole" value="Developer" />
<add key="MvcSiteMapProvider_UseExternalDIContainer" value="false" />
<add key="MvcSiteMapProvider_ScanAssembliesForSiteMapNodes" value="false" />
<add key="MvcSiteMapProvider_IncludeAssembliesForScan" value="Triton.Web" />
<add key="MvcSiteMapProvider_SecurityTrimmingEnabled" value="true" />
<add key="MvcSiteMapProvider_AttributesToIgnore" value="type" />
<add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider" />
<add key="mvc" />
<add key="Twilio.Sid" value="PNf8944dec9bf751ad111f87e1a7ece2b3" />
<add key="Twilio.Token" value="2d1a16e5f7109c56307cc6b696ff1de4" />
<add key="Twilio.Phone" value="3362522181" />

关于如何解决这个问题有什么想法吗?

编辑 我忘了提到当 运行 在本地使用连接字符串指向生产 SQL 服务器时,这不是问题,但我还是会提供我的 connection string

<add name="DefaultConnection" connectionString="Data Source=localhost;Initial Catalog=name; User ID=user;Password=password;Integrated Security=False;" providerName="System.Data.SqlClient" />

将以下代码添加到我的 web.config 中解决了我的问题。这会覆盖托管公司服务器上的其他密钥配置文件。

<membership>
  <providers>
    <clear />
    <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
  </providers>
</membership>
<profile>
  <providers>
    <clear />
    <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="DefaultConnection" applicationName="/" />
  </providers>
</profile>
<roleManager enabled="false">
  <providers>
    <clear />
    <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="DefaultConnection" applicationName="/" />
    <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
  </providers>
</roleManager>

安全修整为 SiteMap 中的每个节点创建一个控制器实例。尽管它不与 entity framework 交互,dollars to donuts 的一个或多个控制器构造函数会交互。

要使用此功能,重要的是遵循以 DI 为中心的控制器方法,即使您实际上并未使用 DI。换句话说,构造函数应该总是简单而轻量——它们应该只做分配依赖项(无论你是否真的可以将它们传递给构造函数)。请参阅 this answer 了解解决构造函数问题的几种解决方案。

另一种可能性是您有一个 AuthorizeAttribute 的自定义子类,它可以调用数据库。如果不需要他们来确定用户是否已获得授权,则您应该像 Microsoft 一样使用处理程序来推迟这些调用。 MvcSiteMapProvider 不执行处理程序,但它执行确定用户是否被授权的逻辑。

这是来自 MVC 5.2 的 AuthorizeAttribute 的片段(通过 Reflector):

/* Defer execution of result to a handler */
protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    filterContext.Result = new HttpUnauthorizedResult();
}

public virtual void OnAuthorization(AuthorizationContext filterContext)
{
    if (filterContext == null)
    {
        throw new ArgumentNullException("filterContext");
    }
    if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
    {
        throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
    }
    if (!filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) && !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
    {
        if (this.AuthorizeCore(filterContext.HttpContext))
        {
            HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
            cache.SetProxyMaxAge(new TimeSpan(0L));
            cache.AddValidationCallback(new HttpCacheValidateHandler(this.CacheValidateHandler), null);
        }
        else
        {
            this.HandleUnauthorizedRequest(filterContext);
        }
    }
}