【问题标题】:Granting access to one db to users/roles of another将一个数据库的访问权限授予另一个用户/角色
【发布时间】:2012-06-18 10:53:06
【问题描述】:

短版:我可以授予角色访问外部数据库的权限吗?

加长版:

我正在使用 Crystal 从应用程序 SQL Server 实例 (database1) 中检索数据来处理报表。

应用程序正在运行报表并覆盖报表中的连接,我无权访问应用程序代码。

我已向服务器 (database2) 添加了一个新数据库,该数据库正在从电话交换机收集信息,我想将其中一些信息加入应用程序数据 (database1)。

当在设计器中运行(以 SA 身份登录)时,我可以加入数据和报告工作,但当报告通过应用程序在外部运行时,它们会失败并出现相当普遍的错误(无法检索数据)。

我假设错误是由新的数据库权限引起的,就好像我以 SA 身份登录应用程序时,错误消失了。

应用程序对运行报告的用户有一个特殊的 DB 角色,当向应用程序 db (database1) 添加表/视图/sp 时,我可以简单地将 select/execute 授予此角色以允许报告访问对象。

现在我在不同的数据库中有对象,但是该角色不容易访问。

有什么方法可以通过现有角色引用第二个数据库 (database2)?

例如:

USE [database1]
GRANT EXECUTE ON [database2].[dbo].[CUSTOM_PROCEDURE] TO [applicationrole1] 

OR

USE [database2]
GRANT EXECUTE ON [dbo].[CUSTOM_PROCEDURE] TO [database1].[dbo].[applicationrole1]

理想情况下,我希望能够以某种方式链接到角色,而不是重新创建新角色,因为当添加/配置新用户时,应用程序会定期更新角色。

(未使用 Crystal-Reports 标记,因为这与问题无关)

编辑:

有什么办法可以做到:

INSERT INTO Database2.sys.database_principals
SELECT * FROM Database1.sys.database_principals
WHERE [type] = 'S'

复制用户(不是登录),然后添加角色成员?

【问题讨论】:

    标签: sql sql-server sql-server-2008 security tsql


    【解决方案1】:

    大概,您将使用可以访问两个数据库的登录名(例如 SA 的情况)。您将创建适当的角色并授予每个数据库的权限,然后在两者中创建用户(链接到您正在使用的登录名),将每个用户添加到您创建的角色中。

    T-SQL 看起来像这样:

    use master
    go
    create login testuser with password = 'mypassword123'
    go
    
    use test
    go
    
    create role reporting
    grant select on something to reporting -- grant your permissions here
    
    create user testuser for login testuser
    exec sp_addrolemember 'reporting', 'testuser'
    go
    
    use test2
    go
    
    create role reporting
    grant select on something2 to reporting -- grant your permissions here
    
    create user testuser for login testuser
    exec sp_addrolemember 'reporting', 'testuser'
    go
    

    现在我可以连接到test 并执行

     select * from something
     select * from test2.dbo.something2
    

    当然,您可以将所需存储过程的授权更改为 EXECUTE,但看起来您已经掌握了这一点。

    之后,只需执行一个简单的脚本来创建登录名、用户并将其添加到角色中。

    declare @sql nvarchar(max), @username nvarchar(50), @password nvarchar(50)
    
    -- ########## SET PARAMETERS HERE
    SET @username = N'testguy'
    SET @password = N'test123'
    -- ########## END SET PARAMETERS
    
    set @sql = N'USE master; CREATE LOGIN [' + @username + N'] WITH PASSWORD = N''' + @password + N'''; USE database1; CREATE USER [' + @username + N'] FOR LOGIN [' + @username + N']; EXEC sp_addrolemember ''reporting'', ''' + @username + N''';  USE database2; CREATE USER [' + @username + N'] FOR LOGIN [' + @username + N']; EXEC sp_addrolemember ''reporting'', ''' + @username + N''';'
    exec sp_executesql @sql
    

    自动同步登录名、用户和角色

    此脚本将查找所有 SQL 登录名(您可以将其更改为对您有意义的任何内容;windows 和 SQL 帐户、包含特定字符串的帐户等),确保用户已在 database1 和 @987654326 中创建@,并确保它们都被添加到reporting 角色中。您需要确保在两个数据库上都创建了 reporting 角色,但您只需执行一次。

    之后,您可以手动或使用 SQL 代理作业定期运行此脚本。您需要做的就是为服务器创建登录名;当脚本运行时,它会完成剩下的工作。

    declare @login nvarchar(50), @user1 nvarchar(50), @user2 nvarchar(50), @sql nvarchar(max), @rolename nvarchar(50)
    
    SET @rolename = 'reporting'
    
    declare c cursor for 
    select sp.name as login, dp1.name as user1, dp2.name as user2 from sys.server_principals as sp
        left outer join database1.sys.database_principals as dp1 on sp.sid = dp1.sid
        left outer join database2.sys.database_principals as dp2 on sp.sid = dp2.sid
    where sp.type = 'S' 
        and sp.is_disabled = 0
    
    open c
    
    fetch next from c into @login, @user1, @user2
    
    while @@FETCH_STATUS = 0 begin
    
        -- create user in db1
        if (@user1 is null) begin
            SET @sql = N'USE database1; CREATE USER [' + @login + N'] FOR LOGIN [' + @login + N'];'
            EXEC sp_executesql @sql
        end
    
        -- ensure user is member of role in db1
        SET @sql = N'USE database1; EXEC sp_addrolemember '''+ @rolename + ''', ''' + @login + N''';'
        EXEC sp_executesql @sql
    
         -- create user in db2
        if (@user2 is null) begin
            SET @sql = N'USE database2; CREATE USER [' + @login + N'] FOR LOGIN [' + @login + N'];'
            EXEC sp_executesql @sql
        end
    
        -- ensure user is member of role in db2
        SET @sql = N'USE database2; EXEC sp_addrolemember '''+ @rolename + ''', ''' + @login + N''';'
        EXEC sp_executesql @sql
    
        fetch next from c into @login, @user1, @user2
    end
    
    
    close c
    deallocate c
    

    您会想要添加事务和错误处理以取消不完整的更改,但我会留给您。

    【讨论】:

    • 有没有办法为添加到database1的新用户完成此操作?
    • 对于您需要添加的任何其他用户,只需在每个数据库上使用 CREATE USER [user name] FOR LOGIN [login name]exec sp_addrolemember ... 部分(如果您已经在每个数据库中创建了用户,则可以省略 CREATE USER 部分,比如说,通过管理工作室)。
    • 经常添加新用户,每次都必须运行这些脚本可能会很困难。有没有办法镜像登录?
    • 好的。是的,您可以同步database2 中缺少的帐户,这些帐户在database 上。我将编写一个额外的脚本。然后,您可以安排一个作业以在任何有意义的时间间隔运行此脚本,因此您所要做的就是担心创建登录。
    • 我添加了我之前提到的脚本。
    【解决方案2】:

    将存储过程设置为所有者执行。

    http://msdn.microsoft.com/en-us/library/ms188354.aspx

    在存储过程所在的数据库上设置trustworthy。

    http://technet.microsoft.com/en-us/library/ms187861.aspx

    确保两个数据库的所有者相同。

    http://msdn.microsoft.com/en-us/library/ms188676(v=sql.105).aspx

    将存储过程的执行权限授予具有该过程的数据库上的适当用户或角色。

    【讨论】:

    • 我已经尝试了这四个步骤,但仍然弹出应用程序错误,我也尝试在database1中创建一个存储过程,调用database2中的proc,但它仍然错误。跨度>
    猜你喜欢
    • 2023-04-07
    • 2022-01-14
    • 1970-01-01
    • 2022-09-26
    • 2020-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多