服务器主体无法访问 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 >>
按钮才能显示连接属性和其他选项卡。
【讨论】:
这对我有用,因为我登录的用户只能访问特定的数据库。谢谢!【参考方案7】:即使用户已正确映射到登录名,我们也遇到了同样的错误。
在尝试删除该用户后,发现一些 SP 包含“with execute as”该用户。
问题已通过删除这些 SP、删除用户、重新创建链接到登录的用户以及重新创建 SP 来解决。
它可能是从备份恢复(在相关登录不存在期间)或批量模式同步(如果可以创建一个带有执行的 SP,即使用户不存在)。也可能与this answer 有关。
【讨论】:
您能否详细说明您所说的 SP 是什么意思? 存储过程。在创建 SP(create proc xxx ...)时,有一个可选子句“with execute as我在 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 服务器主体拥有一个或多个端点无法删除;错误15141