【问题标题】:T-SQL Script current user database permissionsT-SQL 脚本当前用户数据库权限
【发布时间】:2013-03-01 11:15:37
【问题描述】:

有时我必须将数据库从我们的生产 SQL 服务器恢复到测试 SQL 实例。当数据库恢复后,我们手动为恢复的数据库恢复正确的访问权限(例如数据库所有者/读取器/写入器)。此过程运行良好,除了必须在还原之前手动截取权限,然后从拍摄的图像中重新应用它们。

是否有一种简单的方法可以在数据库还原之前使用 T-SQL 存储用户的当前权限,然后在还原完成后重新应用这些相同的权限?

【问题讨论】:

    标签: sql tsql user-permissions


    【解决方案1】:

    您的问题的答案很可能是杰夫的答案。

    但是 Howard 的脚本非常实用,我只是添加了一个列,它会生成带有信息的 TSQL 语法。您可以将其复制并作为 SQL 运行以将权限“复制”到另一个数据库。

    SELECT 
    dp.permission_name collate latin1_general_cs_as    AS Permission,
    t.TABLE_SCHEMA + '.' + o.name AS Object,
    dpr.name AS Username
    , 'GRANT ' + dp.permission_name collate latin1_general_cs_as 
        + ' ON ' 
        + t.TABLE_SCHEMA 
        + '.' 
        + o.name 
        + ' TO ' 
        +  dpr.name
    FROM sys.database_permissions AS dp
    INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
    INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
    INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
    INNER JOIN INFORMATION_SCHEMA.TABLES t
        ON  TABLE_NAME = o.name                
    WHERE dpr.name NOT IN ('public','guest')
    ORDER BY
       Permission, Object,Username
    

    【讨论】:

    • 他说的是权限,但他接着说他的意思是角色成员,这个脚本没有这样做。
    • 这很好,但不适用于存储过程。我必须手动编写这些脚本,即 GRANT EXECUTE ON...
    【解决方案2】:

    有一个非常有用的功能: sys.fn_my_permissions ( 安全 , 'securable_class' ) 它使您可以查看当前用户对指定对象的 EFFECTICVE 权限,所以我不知道您是否可以简单地从中构建 GRANT/DENY 命令。我从来没有那样用过。 在您的情况下,您将以另一个用户身份运行它:

    EXECUTE AS USER = '<username>';
    GO
    SELECT *
    FROM fn_my_permissions(null, 'SERVER') 
    GO
    
    SELECT *
    FROM fn_my_permissions('<DBNAME>', 'Database')
    ORDER BY subentity_name, permission_name ;
    
    REVERT;
    GO
    

    【讨论】:

    • 感谢您的回复 :) 是的,这是一个非常有用的功能。你知道是否有办法以 t-sql 格式返回权限,以便可以通过运行返回的脚本轻松地重新应用它们?
    【解决方案3】:
    SELECT 
    dp.permission_name collate latin1_general_cs_as    AS Permission,
    t.TABLE_SCHEMA + '.' + o.name AS Object,
    dpr.name AS Username
    FROM sys.database_permissions AS dp
    INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
    INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
    INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
    INNER JOIN INFORMATION_SCHEMA.TABLES t
            ON  TABLE_NAME = o.name                
    WHERE dpr.name NOT IN ('public','guest')
    ORDER BY
      Permission, Object,Username
    

    【讨论】:

      【解决方案4】:

      这是@Fabian 编写的脚本的修改版本,这样我还可以编写存储过程的权限脚本。还添加了 QUOTENAME,因此适当的内容放在括号中。

      SELECT 
          dp.permission_name collate latin1_general_cs_as    AS Permission,
          t.TABLE_SCHEMA + '.' + o.name AS TableName,
          rt.ROUTINE_SCHEMA + '.' + o.name AS ProcedureName,
          dpr.name AS Username
          , 'GRANT ' + dp.permission_name collate latin1_general_cs_as 
              + ' ON ' 
              + QUOTENAME(CASE WHEN t.TABLE_SCHEMA IS NOT NULL THEN t.TABLE_SCHEMA ELSE rt.ROUTINE_SCHEMA END )
              + '.' 
              + QUOTENAME(o.name)
              + ' TO ' 
              +  QUOTENAME(dpr.name)
      FROM sys.database_permissions AS dp
      INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
      INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
      INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
      LEFT outer JOIN INFORMATION_SCHEMA.TABLES t ON  TABLE_NAME = o.name              
      LEFT OUTER JOIN INFORMATION_SCHEMA.ROUTINES rt ON rt.ROUTINE_NAME = o.name
      WHERE dpr.name NOT IN ('public','guest')
      ORDER BY Permission, TableName, ProcedureName, Username
      

      【讨论】:

        【解决方案5】:

        您正在处理的问题称为orphaned users

        这是我过去使用过的一个脚本(我不得不凭记忆把它放在一起,你应该仔细验证一下):

        create table #users (UserName sysname, UserSID varbinary(85))
        
        Insert into #users
        exec sp_change_users_login @Action='Report';
        
        declare mycursor cursor for select * from #users;
        open mycursor;
        
        declare @UserName sysname;
        declare @UserSID varbinary(85);
        
        fetch next from mycursor
        into @UserName, @UserSID
        
        while @@FETCH_STATUS = 0
        begin
            exec  sp_change_users_login @Action='update_one', @UserNamePattern=@UserName, @LoginName=@UserName;
        end
        close mycursor;
        deallocate mycursor;
        

        这个脚本做了一个重要的假设。用户登录名和他们在数据库中的用户名匹配。如果不是这样,您将不得不更改发送到 sp_change_users_login 的 @LoginName 参数。

        【讨论】:

        • 非常感谢您的回复 :) 您的脚本是有效的,但问题不在于孤立用户。我需要一种在数据库恢复之前为用户权限编写脚本的方法。之后我将使用所述脚本重新应用记录的权限。我说得有道理吗? ://
        【解决方案6】:

        将此与有关权限的答案结合起来:

        SELECT 'EXEC sp_addrolemember @rolename ='
        + SPACE(1) + QUOTENAME(USER_NAME(rm.role_principal_id), '')
        + ', @membername =' + SPACE(1) + QUOTENAME(USER_NAME(rm.member_principal_id), '') 
        AS 'Role Memberships'
        FROM sys.database_role_members AS rm
        ORDER BY rm.role_principal_id
        

        【讨论】:

          猜你喜欢
          • 2016-01-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-20
          • 2012-04-20
          • 2021-03-02
          • 1970-01-01
          相关资源
          最近更新 更多