启用安全修整的 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);
}
}
}
当我 运行 我的 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);
}
}
}