服务器主体无法访问 SQL Server MS 2012 中当前安全上下文下的数据库

Posted

技术标签:

【中文标题】服务器主体无法访问 SQL Server MS 2012 中当前安全上下文下的数据库【英文标题】:The server principal is not able to access the database under the current security context in SQL Server MS 2012 【发布时间】:2013-10-01 07:33:17 【问题描述】:

我正在尝试通过 SQL Server Management Studio 访问我的托管服务器的数据库,在登录之前一切正常,但是当我使用命令 use myDatabase 时,它给了我这个错误:

The server principal "****" is not able to access the database "****" under the current security context.

我搜索了一遍,托管服务提供商列出了this 解决问题。

但这对我不起作用,可能是因为它适用于 SQL Server Management Studio 2008,但我使用的是 SQL Server Management Studio 2012。

这可能是个问题吗?如果是的话,谁能告诉我它在 SSMS 2012 中的替代方案?

【问题讨论】:

'托管服务提供商'?我们是在谈论专用的还是共享的?如果它是共享托管服务器,我强烈建议您联系您的托管服务提供商寻求帮助。共享主机环境中的 SQL 是出了名的错误和问题。它与产品无关,而是托管服务提供商应用于服务器的策略。每个托管公司都有自己的方式来利用 SQL,或者看起来如此。 【参考方案1】:

我遇到了一个特定于 USER WITHOUT LOGIN 的问题,在将数据库备份并还原到另一台服务器后,用户失去了与数据库的连接。

为了解决这个问题,我们需要确保用户已连接到数据库。

GRANT CONNECT TO [DatabaseUser]
GO

这类似于上面 Salim Gangji 给出的答案,但特定于 USER WITHOUT LOGIN 的情况。

【讨论】:

【参考方案2】:

SQL Logins 是在服务器级别定义的,必须映射到特定数据库中的Users

在 SSMS 对象资源管理器中,在您要修改的服务器下,展开 Security > Logins,然后双击相应的登录条目。这将打开“登录属性”对话框。

选择用户映射,这将显示服务器上的所有数据库。那些已经将用户映射到该登录名的用户将选中“映射”复选框。从这里您可以选择其他数据库(并确保在每个数据库中选择用户应属于的角色),然后单击确定添加映射。

请注意,虽然通常将用户命名为与登录名相同以避免混淆,但它们不必匹配,您可以随意命名用户。

在还原或类似操作后,这些映射可能会断开连接。在这种情况下,用户可能仍然存在于数据库中,但实际上并未映射到登录名。如果发生这种情况,您可以运行以下命令来恢复登录:

USE database;
ALTER USER user WITH login = login

您也可以删除数据库用户并从“登录属性”对话框重新创建它,但任何角色成员资格或其他设置都需要重新创建。

【讨论】:

您的评论应该是公认的答案。它清楚地描述了: - SQL 登录位于 服务器级别 - SQL 用户位于 Db 级别 - 将登录映射到用户 缺少操作项 很好的答案。这正是我所需要的。谢谢!【参考方案3】:

在 SQL 2017 上 - 数据库 A 具有数据库 B 的同义词。用户可以连接到数据库 A,并且对指向 B 的同义词的 sp(在 A 上)拥有执行权限。用户设置为连接访问 B . 只有当向数据库 B 的公共组授予 CONNECT 时,A 上的 sp 才起作用。我不记得在 2012 年以这种方式工作,因为仅授予用户连接似乎有效。

【讨论】:

【参考方案4】:

我相信您在创建数据库用户时可能缺少“Grant Connect To”语句。

下面是完整的 sn-p,您需要创建针对 SQL Server DBMS 的登录以及针对数据库的用户

USE [master]
GO

CREATE LOGIN [SqlServerLogin] WITH PASSWORD=N'Passwordxyz', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=OFF, CHECK_POLICY=ON
GO

USE [myDatabase]
GO

CREATE USER [DatabaseUser] FOR LOGIN [SqlServerLogin] WITH DEFAULT_SCHEMA=[mySchema]
GO

GRANT CONNECT TO [DatabaseUser]
GO

-- the role membership below will allow you to run a test "select" query against the tables in your database
ALTER ROLE [db_datareader] ADD MEMBER [DatabaseUser]
GO

【讨论】:

【参考方案5】:

这对我有用:

use <Database>
EXEC  sp_change_users_login @Action='update_one', @UserNamePattern='<userLogin>',@LoginName='<userLogin>';

问题可以通过以下方式可视化:

SELECT sid FROM sys.sysusers WHERE name = '<userLogin>'
SELECT sid FROM sys.syslogins WHERE name = '<userLogin>';

【讨论】:

这为我解决了问题。谢谢 ! “这个问题可以用“可视化” -> 如果它们返回不同的哈希,则存在问题,上面的查询将同步它们。【参考方案6】:

我花了很长时间来解决这个问题,然后我意识到我犯了一个简单的错误,因为我忘记了我的连接目标是哪个特定数据库。我使用标准 SQL Server 连接窗口来输入凭据:

我必须检查 连接属性 选项卡以确认我选择了正确的数据库进行连接。我不小心将此处的 连接到数据库 选项设置为上一个会话的选择。这就是为什么我无法连接到我认为我正在尝试连接的数据库。

请注意,您需要单击Options &gt;&gt; 按钮才能显示连接属性和其他选项卡。

【讨论】:

这对我有用,因为我登录的用户只能访问特定的数据库。谢谢!【参考方案7】:

即使用户已正确映射到登录名,我们也遇到了同样的错误。

在尝试删除该用户后,发现一些 SP 包含“with execute as”该用户。

问题已通过删除这些 SP、删除用户、重新创建链接到登录的用户以及重新创建 SP 来解决。

它可能是从备份恢复(在相关登录不存在期间)或批量模式同步(如果可以创建一个带有执行的 SP,即使用户不存在)。也可能与this answer 有关。

【讨论】:

您能否详细说明您所说的 SP 是什么意思? 存储过程。在创建 SP(create proc xxx ...)时,有一个可选子句“with execute as ”指定 SP 将像该用户运行它而不是当前登录的用户一样运行。跨度> 【参考方案8】:

我在 vb.net 中使用服务器管理对象 (SMO) 时遇到了同样的错误(我确定在 C# 中也是如此)

Techie Joe 对最初帖子的评论是一个有用的警告,即在共享托管中会发生许多其他事情。花了一点时间才弄清楚,但下面的代码显示了访问 SQL 数据库的方式必须非常具体。每当 SMO 调用在共享托管环境中不精确时,似乎就会出现“服务器主体.​​..”错误。

第一部分代码针对本地 SQL Express 服务器,并依赖于简单的 Windows 身份验证。这些示例中使用的所有代码均基于 Robert Kanasz 在此Code Project website article 中的 SMO 教程:

  Dim conn2 = New ServerConnection()
  conn2.ServerInstance = "<local pc name>\SQLEXPRESS"
  Try
    Dim testConnection As New Server(conn2)
    Debug.WriteLine("Server: " + testConnection.Name)
    Debug.WriteLine("Edition: " + testConnection.Information.Edition)
    Debug.WriteLine(" ")

    For Each db2 As Database In testConnection.Databases
      Debug.Write(db2.Name & " - ")
      For Each fg As FileGroup In db2.FileGroups
        Debug.Write(fg.Name & " - ")
        For Each df As DataFile In fg.Files
          Debug.WriteLine(df.Name + " - " + df.FileName)
        Next
      Next
    Next
    conn2.Disconnect()

  Catch err As Exception
    Debug.WriteLine(err.Message)
  End Try

上面的代码可以很好地找到本地 SQLEXPRESS 服务器上每个数据库的 .mdf 文件,因为身份验证是由 Windows 处理的,而且它在所有数据库中都很广泛。

在以下代码中,有 2 个部分对 .mdf 文件进行迭代。在这种情况下,只有寻找文件组的第一次迭代有效,并且它只找到一个文件,因为连接只连接到共享主机环境中的一个数据库。

第二次迭代是上述迭代的副本,它立即阻塞,因为它的编写方式试图访问共享环境中的第一个数据库,而不是用户 ID/密码的数据库应用,因此 SQL 服务器以“服务器主体.​​..”错误的形式返回授权错误。

Dim sqlConnection1 As New System.Data.SqlClient.SqlConnection
sqlConnection1.ConnectionString = "connection string with User ID/Password to a specific database in a shared hosting system. This string will likely also include the Data Source and Initial Catalog parameters"
Dim conn1 As New ServerConnection(sqlConnection1)
Try
  Dim testConnection As New Server(conn1)
  Debug.WriteLine("Server: " + testConnection.Name)
  Debug.WriteLine("Edition: " + testConnection.Information.Edition)
  Debug.WriteLine(" ")

  Dim db2 = testConnection.Databases("the name of the database to which the User ID/Password in the connection string applies")
  For Each fg As FileGroup In db2.FileGroups
    Debug.Write(fg.Name & " - ")
    For Each df As DataFile In fg.Files
      Debug.WriteLine(df.Name + " - " + df.FileName)
    Next
  Next

  For Each db3 As Database In testConnection.Databases
    Debug.Write(db3.Name & " - ")
    For Each fg As FileGroup In db3.FileGroups
      Debug.Write(fg.Name & " - ")
      For Each df As DataFile In fg.Files
        Debug.WriteLine(df.Name + " - " + df.FileName)
      Next
    Next
  Next

  conn1.Disconnect()

Catch err As Exception
  Debug.WriteLine(err.Message)
End Try

在第二次迭代循环中,代码编译良好,但由于 SMO 未设置为使用精确语法准确访问正确的数据库,因此尝试失败。

由于我刚刚学习 SMO,我认为其他新手可能会很高兴知道这个错误还有一个更简单的解释 - 我们只是编码错误。

【讨论】:

【参考方案9】:

在我的情况下,该消息是由无意中在“对象名称”中包含数据库名称的同义词引起的。当我以新名称恢复数据库时,同义词仍指向旧数据库名称。由于用户在旧数据库中没有权限,因此出现了该消息。为了解决这个问题,我删除并重新创建了同义词,而不用数据库名称限定对象名称:

    USE [new_db]
GO

/****** Object:  Synonym [dbo].[synTable]    Script Date: 10/15/2015 9:45:01 AM ******/
DROP SYNONYM [dbo].[synTable]
GO

/****** Object:  Synonym [dbo].[synTable]    Script Date: 10/15/2015 9:45:01 AM ******/
CREATE SYNONYM [dbo].[synTable] FOR [dbo].[tTheRealTable]
GO

【讨论】:

【参考方案10】:

在我们的 PROD 环境中向 s-s-rS 部署报告时遇到了同样的错误。发现这个问题甚至可以用“use”语句来重现。解决方案是将用户的 GUID 帐户引用与相关数据库重新同步(即,像在恢复数据库后一样使用“sp_change_users_login”)。附上用于重新同步所有帐户的股票(光标驱动)脚本:

USE <your database>
GO

-------- Reset SQL user account guids ---------------------
DECLARE @UserName nvarchar(255) 
DECLARE orphanuser_cur cursor for 
      SELECT UserName = su.name 
      FROM sysusers su
      JOIN sys.server_principals sp ON sp.name = su.name
      WHERE issqluser = 1 AND
            (su.sid IS NOT NULL AND su.sid <> 0x0) AND
            suser_sname(su.sid) is null 
      ORDER BY su.name 

OPEN orphanuser_cur 
FETCH NEXT FROM orphanuser_cur INTO @UserName 

WHILE (@@fetch_status = 0)
BEGIN 
--PRINT @UserName + ' user name being resynced' 
exec sp_change_users_login 'Update_one', @UserName, @UserName 
FETCH NEXT FROM orphanuser_cur INTO @UserName 
END 

CLOSE orphanuser_cur 
DEALLOCATE orphanuser_cur

【讨论】:

为我工作谢谢。我已将具有 SQL 服务器身份验证的数据库复制到我的测试服务器,但无法访问。现在是 如果用户存在于数据库中但未能持久映射到登录名,则通过 SSMS 对象资源管理器删除所述用户然后重新映射登录名对我有用。否则,我怀疑需要采用上面提出的解决方案。【参考方案11】:

检查您的用户是否映射到您尝试登录的数据库。

【讨论】:

@Graham 使用 SQL Server Management Studio 检查用户或查看此答案:***.com/a/9356725/804773 我建议寻找触发器,这就是我收到此消息的原因,有一个触发器在我的用户未授权的另一个数据库中执行某些操作。 我遇到了 OP 的错误并拒绝了这个答案,我发现我只是在连接到 Azure SQL 数据库的连接字符串中的数据库名称中有一个愚蠢的错字。如果您的数据库名称正确,则不需要访问 Master。如果它是错误的,那么(在我的情况下)我认为实体框架(6.1.3)试图通过连接到 Master 以获得一些额外的信息来变得更加聪明(尽管这可能与 EF 无关——我不确定)。但我的解决方案是确保我的连接字符串是正确的。对于错误的数据库名称,我预计会出现非常不同的错误。 :-/ 要添加到@DanielV 的评论中,还要检查存储过程以获取任何硬编码的数据库名称。在我的情况下修复了它(大约 20 个存储过程必须更改)。 @scott 被映射到。

以上是关于服务器主体无法访问 SQL Server MS 2012 中当前安全上下文下的数据库的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server服务器级别角色

SQL SERVER 主体,已同步

SQL Server 服务器主体拥有一个或多个端点无法删除;错误15141

Sql Server中不存在原理dbo

在 C#.NET 中对 SQL Server 的 MS 访问

如何在 ms 访问中显示来自 sql server 的图像