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


103

我正在尝试通过SQL Server Management Studio访问托管服务器的数据库,直到登录正常为止一切正常,但是当我使用该命令use myDatabase时,出现以下错误:

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

我进行了搜索,托管服务提供商已列出了问题的修复程序。

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

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


3
“托管服务提供商”?我们是专门讨论还是共享?如果是共享托管服务器,我强烈建议您与托管提供商联系以寻求帮助。众所周知,共享托管环境中的SQL有错误和问题。它与产品无关,但托管提供者将策略应用于服务器。似乎每个托管公司都有自己的利用SQL的方式。
Techie Joe

Answers:


80

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


75
你是怎样做的?
格雷厄姆

3
@Graham可以使用SQL Server Management Studio来检查用户,也可以查看以下答案:stackoverflow.com/a/9356725/804773
Grambot 2014年

5
我建议寻找触发器,这就是我收到此消息的原因,有一个触发器在另一个未授权我的用户的数据库中做一些事情。
DanielV

1
我碰到了OP的错误并拒绝了这个答案,我发现我在连接到Azure SQL数据库的连接字符串中的数据库名称中只是一个愚蠢的错字。如果您的数据库名称正确,则您不需要访问Master。如果是错的话,那么(以我为例)我认为实体框架(6.1.3)试图通过连接到Master获得一些其他信息来变得更加聪明(尽管这可能与EF无关-我不确定)。但是我的解决方案是确保我的连接字符串正确。对于错误的数据库名称,我预期会有一个非常不同的错误。:-/
Jaxidian

2
要添加到@DanielV的注释中,还请检查存储过程中是否有任何硬编码的数据库名称。在我的情况下已修复(必须更改约20个存储过程)。
Demonslay335 '18 / 12/21

26

在PROD环境中将报告部署到SSRS时,我们也遇到了同样的错误。发现问题甚至可以通过“ 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

2
为我工作谢谢。我已将具有SQL Server身份验证的数据库复制到测试服务器,但是该数据库无法访问。现在是
MikeH,2016年

1
如果用户存在于数据库中,但无法持久保存到登录名的映射,请通过SSMS Object Explorer删除该用户,然后重新映射登录名对我有用。否则,我怀疑需要采取以上提议的解决方案。
jjt

10

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

SQL Server连接窗口

我必须检查“ 连接属性”选项卡以验证是否选择了要连接的正确数据库。我不小心此处的“ 连接到数据库”选项设置为上一个会话的选择。这就是为什么我无法连接到我连接的数据库的原因。

连接属性

请注意,您需要单击Options >>按钮以显示“ 连接属性”和其他选项卡。


10

这对我有用:

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>';

2
这为我解决了。谢谢 !“问题可以通过可视化”->如果它们返回不同的哈希值,则说明存在问题,上面的查询将对其进行同步。
bezout

6

SQL 登录名是在服务器级别定义的,必须映射到特定数据库中的“ 用户”

在SSMS对象资源管理器中,要修改的服务器下,展开“ 安全性” >“ 登录名”,然后双击相应的用户,这将弹出“登录属性”对话框。

选择User Mapping,它将显示服务器上的所有数据库,以及已选择现有映射的数据库。在这里,您可以选择其他数据库(并确保选择用户应属于每个数据库中的哪个角色),然后单击“ 确定”以添加映射。

在此处输入图片说明

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

USE {database};
ALTER USER {user} WITH login = {login}

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


4

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

    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

2

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

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

通过删除这些SP,删除用户,重新创建链接到登录名的用户以及重新创建SP,解决了该问题。

可能是由于从备份还原(在相关的登录名不存在时)或批量模式同步(如果有可能即使用户不存在也可以通过execute创建SP)进入这种状态。与这个答案有关


1
您能否详细说明SP的含义?
Scuba Steve

1
存储过程。创建SP时(创建proc xxx ...),有一个可选的子句“ with execute as <user>”,它指定SP的运行就像该用户已运行该SP一样,而不是当前登录的用户。
crokusek

1

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

Techie Joe在最初的帖子中发表的评论是一个有用的警告,即在共享主机中还有许多其他事情正在进行。花了一点时间弄清楚,但是下面的代码显示了如何访问SQL数据库必须非常具体。每当共享主机环境中的SMO调用不完全特定时,“服务器主体.​​..”错误似乎就会出现。

代码的第一部分针对本地SQL Express服务器,并且依赖于简单的Windows身份验证。这些示例中使用的所有代码均基于Robert Kanasz在此Code Project网站文章中的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 Server以“服务器主体.​​..”错误的形式返回授权错误。

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时,我想其他新手可能会喜欢,知道对此错误还有一个更简单的解释-我们只是将其编码为错误。


0

我相信您在创建数据库用户时可能会丢失“授权连接到”语句。

下面是完整的代码段,您将需要创建针对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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.