从ASP.NET访问“用户实例”数据库时出现用户权限错误

26

csharpindepth.com的服务器最近已经迁移。

它的大部分功能都正常工作,但我无法使用用于保存勘误、笔记等内容的数据库。

相关细节:

  • 32位Windows Server 2003
  • 已安装SQL Server Express 2005
  • ASP.NET池在“NETWORK SERVICE”帐户下运行
  • .NET 3.5
  • 每个人都对数据库文件有完全的访问权限(目前仅为排除此原因!)
  • 连接字符串:

Data Source=.;AttachDbFilename=|DataDirectory|\WebSiteData.mdf;
Integrated Security=True;User Instance=True
  • 我只需创建一个新的WebSiteDataContext(它的默认连接字符串如上所述)即可连接。

  • 使用一个小的测试控制台应用程序从包含文件的目录运行,作为管理员帐户,使用相同的查询,我可以看到数据库的内容。

    在ASP.NET中,我得到了这个异常:

    SqlException (0x80131904): User does not have permission to perform this action.
    

    编辑:更多信息,以下是堆栈跟踪:

    [SqlException (0x80131904): User does not have permission to perform this action.]
       System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +4844759
       System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +194
       System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2392
       System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK) +35
       System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnection owningObject) +144
       System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(String host, String newPassword, Boolean redirectedUserInstance, SqlConnection owningObject, SqlConnectionString connectionOptions, Int64 timerStart) +342
       System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(SqlConnection owningObject, SqlConnectionString connectionOptions, String newPassword, Boolean redirectedUserInstance) +221
       System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, Object providerInfo, String newPassword, SqlConnection owningObject, Boolean redirectedUserInstance) +189
       System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection) +4859187
       System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnection owningConnection, DbConnectionPool pool, DbConnectionOptions options) +31
       System.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject) +433
       System.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject) +66
       System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject) +499
       System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection) +65
       System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory) +117
       System.Data.SqlClient.SqlConnection.Open() +122
       System.Data.Linq.SqlClient.SqlConnectionManager.UseConnection(IConnectionUser user) +44
       System.Data.Linq.SqlClient.SqlProvider.get_IsSqlCe() +45
       System.Data.Linq.SqlClient.SqlProvider.InitializeProviderMode() +20
       System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) +57
       System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +35
    

    编辑:我的关于文件名必须正确的观点是错误的——更改连接字符串以使其与其他文件通信并不能解决错误。

    ProcMon从未显示它接触文件……

    编辑:进一步的奇怪现象——在本地系统帐户下重新启动应用程序池仍然存在问题,这是最奇怪的!好像尽管有错误消息,它实际上正在尝试做一些不可能的事情(例如使用错误的路径),而不仅仅是权限问题。

    编辑:更多信息——我刚刚将小型测试控制台应用程序作为“NETWORK SERVICE”从服务中运行,并且(经过一次超时的初始尝试之后)它成功了。因此,它与用户帐户无关的权限问题......它与其运行的环境有关......


    52
    天啊,Jon Skeet居然提出了一个问题? - rlbond
    9
    我想这里的每个人都知道你的网站,Jon,但我看到有些问题因为提问者没有必要地提及和链接自己的网站而被关闭为垃圾邮件。 - balpha
    7
    澄清一下:我并不是在指责你做了什么事情。我只是想避免给人双重标准的印象。 - balpha
    8
    好的,我会编辑以删除链接。 - Jon Skeet
    12
    我认为他回答了4422个问题,因此我认为他应该得到一个小小的无意插话。 - Brian R. Bondy
    显示剩余10条评论
    9个回答

    6

    孩子实例是否开始运行?当请求 RANU 数据库时,主实例(在本例中为 .\SQLEXPRESS)必须创建一个“子”实例,也就是启动 sqlservr.exe 进程作为用户进程,在以用户身份从 .SQLEXPRESS 实例请求 RANU 连接的凭据下运行。在这种情况下,实例必须以“NETWORK SERVICE”身份启动。

    要验证子实例是否已启动,请连接到主实例(.\SQLEXPRESS)并检查 sys.dm_os_child_instances

    SELECT * 
    FROM sys.dm_os_child_instances
    

    如果启动了一个由NETWORK SERVICE拥有的子实例,请取其instance_pipe_name并直接连接到该子实例:
    sqlcmd -S np:\\.\pipe\<child pipe name>\tsql\query
    

    理想情况下,以NETWORK SERVICE身份连接(例如从以NETWORK SERVICE身份启动的交互式cmd控制台连接,可以使用at.exe在未来1分钟内安排它)。 如果这样操作成功,则最后一步是尝试使用普通的sp_attach_db附加MDF。 这些步骤的目的不是解决问题,而是确定故障原因,因为您得到的错误有点普遍而且...不太有用。

    没有任何迹象表明子实例已启动...我怀疑这就是问题所在,但我无法确定它在哪里失败了。将我的应用程序池更改为以本地系统运行也没有帮助,这非常奇怪。 - Jon Skeet
    以 NETWORK SERVICE 身份启动控制台的最简单方法是什么?尝试以同样的方式运行我的测试应用程序会很有趣... - Jon Skeet
    我知道如何使用AT.exe将其作为系统启动:at 10:45pm /INTERACTIVE cmd(其中10:45pm就像是未来1分钟)。对于NETWORK SERVICE,我不知道如何检索它的密码。除此之外,RUNAS需要它(而且我不确定NETWORK SERVICE是否允许在runas中运行),尝试使用sc.exe创建虚拟服务也需要密码:sc create cmd_as_ns binpath= c:\WINDOWS\system32\cmd.exe start= demand obj= "NETWORK SERVICE"(即使在将cmd.exe包装在srvany.exe中之后也是如此)。 - Remus Rusanu
    @Remus:最终我没有使用at.exe,而是使用了一个服务。不过,我刚刚检查了一下你提到的SQLEXPRESS目录,但它并不存在。在同一位置有一个MSSQLSERVER目录,也许代表着“.”实例……那么我该如何将适当的数据放入SQLEXPRESS目录中呢? - Jon Skeet
    但是无论如何,如果您的子实例正在运行,它是否会打开/附加您选择的MDF文件? - Remus Rusanu
    显示剩余12条评论

    3

    谢谢 - 如果我再遇到这个问题,我会这样做。幸运的是,我已经完全放弃了在这个特定问题上使用数据库。只需一个XML文件就可以胜任,并且更简单 :) - Jon Skeet

    2
    你做过这个吗?
    为了配置 Windows 集成安全的 SQL Server:
    从 Windows 开始菜单中,选择 Microsoft SQL Server,然后选择 Enterprise Manager。
    打开服务器节点并展开要为用户授予权限的数据库节点。
    右键单击“用户”节点,然后选择“新建数据库用户”。
    在“数据库用户属性”对话框中,在“登录名”框中输入 domain\username,然后单击“确定”。此外,配置 SQL Server 允许所有域用户访问数据库。 来源 所以基本上要验证是否在那里列出了“NT AUTHORITY\NETWORK SERVICE”。
    另外,在 SQL 2008 中(至少如此),不确定 2005 的情况下,您也可以在服务器级别上设置它(服务器->安全性->登录)。

    只是在服务器级别上设置,也没有成功。 - Jon Skeet
    也许尝试重新启动SQL服务,然后更改后尝试重新启动w3svc服务。 - Brian R. Bondy
    最好也要验证一下新添加的登录权限。 - Brian R. Bondy
    1
    是的,我重新启动了各种东西。我只希望我能找出哪个进程失败了...似乎没有任何通常的嫌疑人。 - Jon Skeet

    2

    Integrated Security=True

    "Integrated Security=True"是指数据库连接的用户登录信息与计算机用户账户关联,可能存在相关映射问题。


    数据库中没有用户登录信息 - 它只是一个数据库文件。 - Jon Skeet

    1

    如果您正在使用用户实例,那么您连接的方式是管理员方式,这也是为什么不建议在托管方案中使用的原因。我遇到的权限问题通常是文件本身的物理问题,而不是文件夹 - 分离数据库往往会剥夺权限。

    如果您能够缩小异常发生的确切位置,可能会有所帮助。它试图执行什么操作?打开、读取、写入数据库?另外尝试另一个数据库(即,是否是特定的数据库),并尝试非用户实例版本;将数据库附加到实例上。


    我猜你已经检查了你的 SQL Server 是否支持用户实例?请参阅http://msdn.microsoft.com/en-us/library/ms254504(VS.80).aspx。SQLEXPRESS 默认支持此功能,但是你没有连接到 SQLEXPRESS,因此可能未启用。 - Dave Sussman

    0

    我会首先运行filemon(或更好的Process Monitor)来查看IIS进程是否能够打开数据库文件 - 这对我来说似乎是一个安全问题。

    另外:确保~/App_Data文件夹不是只读的。同时,检查是否已经为同一文件夹授予了“Network Service”帐户的完全权限。

    您可能需要运行IISRESET来重新启动IIS并刷新其权限。


    0

    当您说用户对文件具有完全权限时,所有用户是否都对app_data目录具有完全权限?Sql需要在MDF文件旁边创建锁定文件。

    另外,您确定SQL Express实例已启用用户实例吗?


    @blowdart:目录,是的。启用用户实例可能就在那里 - 它在哪里? - Jon Skeet
    我的搭档说他已经检查过用户实例确实已启用。 - Jon Skeet
    好的,尝试暂时移除用户实例参数,看看会发生什么。以防万一它变得非常混乱。反正它们在2010年就要消失了 :) - blowdart
    是的,这以一种相当明确的方式改变了事情:“System.Data.SqlClient.SqlException: 在 SQL Server 中生成用户实例已被禁用。请使用 sp_configure 'user instances enabled' 生成用户实例。” - Jon Skeet
    然后,如果您这样做并切换回来呢?(您可能需要手动先分离数据库) - blowdart
    显示剩余3条评论

    0
    你尝试在服务器上运行aspnet_regsql.exe来重新调整一些东西了吗(有点像偶尔必须运行aspnet_regiis一样)?Scott Gu在这里提供了整个过程的基本概述here

    我不认为它是同一种类型的工具,但无论如何都试了一下。看起来似乎并不适用于用户实例。 - Jon Skeet
    真遗憾,我也是这么想的,直到我看到文章末尾并注意到配置设置带有AttachDbFilename,我想这可能会有所帮助。 - Dillie-O

    0

    由于您的Trusted Authentication=True,连接使用调用进程的安全上下文。这意味着您正在以已登录用户的安全上下文中运行开发服务器,因此一切正常。当您在IIS中运行时,您处于应用程序池进程的安全上下文中,该进程是NETWORK SERVICE,没有用户配置文件,因此会崩溃。

    要修复,请使用解决方案#1或#2。

    1.) 将应用程序池的标识更改为具有对数据库访问权限的普通用户,作为自定义帐户。提示:设置此用户:SELECT owning_principal_name FROM sys.dm_os_child_instances WHERE heart_beat = 'alive'

    2.) 使用带有用户名和密码的连接字符串;即使用SQL Server身份验证,而不是Trusted Authentication=True。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接