web-dev-qa-db-fra.com

Comment écrire le rôle de base de données du serveur SQL?

Je dois créer un script pour copier un rôle de base de données particulier d'un serveur SQL à un autre.

Existe-t-il un moyen simple de générer un script qui crée le rôle et toutes les autorisations associées?

19
Foster Geng

Vous pouvez obtenir ce dont vous avez besoin avec un script comme celui-ci:

declare @RoleName varchar(50) = 'RoleName'

declare @Script varchar(max) = 'CREATE ROLE ' + @RoleName + char(13)
select @script = @script + 'GRANT ' + prm.permission_name + ' ON ' + OBJECT_NAME(major_id) + ' TO ' + rol.name + char(13) COLLATE Latin1_General_CI_AS 
from sys.database_permissions prm
    join sys.database_principals rol on
        prm.grantee_principal_id = rol.principal_id
where rol.name = @RoleName

print @script
25
Alex Aza

J'ai développé la réponse de Mario Eis:

SELECT 'GRANT ' + database_permissions.permission_name + ' ON ' + CASE database_permissions.class_desc
        WHEN 'SCHEMA'
            THEN '[' + schema_name(major_id) + ']'
        WHEN 'OBJECT_OR_COLUMN'
            THEN CASE 
                    WHEN minor_id = 0
                        THEN'['+OBJECT_SCHEMA_NAME(major_id) + '].' + '[' + object_name(major_id) + ']' COLLATE Latin1_General_CI_AS_KS_WS
                    ELSE (
                            SELECT object_name(object_id) + ' (' + NAME + ')'
                            FROM sys.columns
                            WHERE object_id = database_permissions.major_id
                                AND column_id = database_permissions.minor_id
                            )
                    END
        ELSE 'other'
        END + ' TO [' + database_principals.NAME + ']' COLLATE Latin1_General_CI_AS_KS_WS
FROM sys.database_permissions
JOIN sys.database_principals ON database_permissions.grantee_principal_id = database_principals.principal_id
LEFT JOIN sys.objects --left because it is possible that it is a schema
    ON objects.object_id = database_permissions.major_id
WHERE database_permissions.major_id > 0
    AND permission_name IN (
        'SELECT'
        ,'INSERT'
        ,'UPDATE'
        ,'DELETE'
        ,'EXECUTE'
        )
7
mcfea

Ce script génère des instructions GRANT pour vos rôles. J'aime le fait qu'il prenne en charge les autorisations de colonne leven. Il doit être adapté à vos besoins (par exemple, améliorer pour des bases de données plus complexes, concaténer des instructions et exécuter, inclure une instruction pour votre rôle). Mais juste pour vous donner une idée:

SELECT 'GRANT ' + database_permissions.permission_name + ' ON ' +
    CASE database_permissions.class_desc
        WHEN 'SCHEMA' THEN schema_name(major_id)
        WHEN 'OBJECT_OR_COLUMN' THEN
            CASE WHEN minor_id = 0 THEN object_name(major_id) COLLATE Latin1_General_CI_AS_KS_WS
            ELSE (SELECT object_name(object_id) + ' ('+ name + ')'
                  FROM sys.columns 
                  WHERE object_id = database_permissions.major_id 
                  AND column_id = database_permissions.minor_id) end
        ELSE 'other' 
    END + 
    ' TO ' + database_principals.name COLLATE Latin1_General_CI_AS_KS_WS
FROM sys.database_permissions
JOIN sys.database_principals
ON database_permissions.grantee_principal_id = database_principals.principal_id
LEFT JOIN sys.objects --left because it is possible that it is a schema
ON objects.object_id = database_permissions.major_id
WHERE database_permissions.major_id > 0
AND permission_name in ('SELECT','INSERT','UPDATE','DELETE')
4
Mario Eis

DANS SSMS, cliquez avec le bouton droit de la souris sur le nœud utilisateur/login/rôle et sélectionnez "Script as" pour créer un script pour cet utilisateur/login/rôle particulier. Cependant, vous ne pouvez pas écrire le rôle de rôle de rôle de cette façon.

Visual Studio avec l'option 'Database Drvelopment' et Red Gate SQL Compare peut générer le script de changement entre les bases de données, y compris les utilisateurs, les rôles et l'appartenance à un rôle.

Généré par l'appartenance au rôle VS ressemble à ceci:

EXECUTE sp_addrolemember @rolename = N'db_datareader', @membername = N'DOMAIN\User';

Si vous n'avez pas de VS, vous pouvez les écrire manuellement ou créer un script SQL pour les générer.

Je suis sûr qu’il devrait également exister un outil gratuit permettant de faire quelque chose comme cela, mais comme je n’en ai pas besoin car Visual Studio, je ne l’ai jamais cherché.

Edit : Je viens de me rendre compte que je répondais à une mauvaise question. Vous parlez de l’autorisation de rôle et je vous parle de l’appartenance à un rôle. Désolé pour ça. Je laisserai cette réponse ici au cas où cela pourrait être utile à quelqu'un d'autre. Alex Aza a l'air bien.

3
Andrew Savinykh

J'ai créé un script assez complet qui non seulement spécifie toutes les autorisations, mais également tous les membres et permet de givrer le gâteau, formate la sortie pour une copie/un collage facile dans une nouvelle fenêtre de requête. J'ai posté le script sur mon blog et le mets à jour de temps en temps, mais la version actuelle est la suivante, qui devrait couvrir la plupart des bases:

/********************************************************************
 *                                                                  *
 * Author: John Eisbrener                                           *
 * Script Purpose: Script out Database Role Definition              *
 * Notes: Please report any bugs to http://www.dbaeyes.com/         *
 *                                                                  *
 ********************************************************************/
DECLARE @roleName VARCHAR(255)
SET @roleName = 'DatabaseRoleName'

-- Script out the Role
DECLARE @roleDesc VARCHAR(MAX), @crlf VARCHAR(2)
SET @crlf = CHAR(13) + CHAR(10)
SET @roleDesc = 'CREATE ROLE [' + @roleName + ']' + @crlf + 'GO' + @crlf + @crlf

SELECT    @roleDesc = @roleDesc +
        CASE dp.state
            WHEN 'D' THEN 'DENY '
            WHEN 'G' THEN 'GRANT '
            WHEN 'R' THEN 'REVOKE '
            WHEN 'W' THEN 'GRANT '
        END + 
        dp.permission_name + ' ' +
        CASE dp.class
            WHEN 0 THEN ''
            WHEN 1 THEN --table or column subset on the table
                CASE WHEN dp.major_id < 0 THEN
                    + 'ON [sys].[' + OBJECT_NAME(dp.major_id) + '] '
                ELSE
                    + 'ON [' +
                    (SELECT SCHEMA_NAME(schema_id) + '].[' + name FROM sys.objects WHERE object_id = dp.major_id)
                        + -- optionally concatenate column names
                    CASE WHEN MAX(dp.minor_id) > 0 
                         THEN '] ([' + REPLACE(
                                        (SELECT name + '], [' 
                                         FROM sys.columns 
                                         WHERE object_id = dp.major_id 
                                            AND column_id IN (SELECT minor_id 
                                                              FROM sys.database_permissions 
                                                              WHERE major_id = dp.major_id
                                                                AND USER_NAME(grantee_principal_id) IN (@roleName)
                                                             )
                                         FOR XML PATH('')
                                        ) --replace final square bracket pair
                                    + '])', ', []', '')
                         ELSE ']'
                    END + ' '
                END
            WHEN 3 THEN 'ON SCHEMA::[' + SCHEMA_NAME(dp.major_id) + '] '
            WHEN 4 THEN 'ON ' + (SELECT RIGHT(type_desc, 4) + '::[' + name FROM sys.database_principals WHERE principal_id = dp.major_id) + '] '
            WHEN 5 THEN 'ON Assembly::[' + (SELECT name FROM sys.assemblies WHERE Assembly_id = dp.major_id) + '] '
            WHEN 6 THEN 'ON TYPE::[' + (SELECT name FROM sys.types WHERE user_type_id = dp.major_id) + '] '
            WHEN 10 THEN 'ON XML SCHEMA COLLECTION::[' + (SELECT SCHEMA_NAME(schema_id) + '.' + name FROM sys.xml_schema_collections WHERE xml_collection_id = dp.major_id) + '] '
            WHEN 15 THEN 'ON MESSAGE TYPE::[' + (SELECT name FROM sys.service_message_types WHERE message_type_id = dp.major_id) + '] '
            WHEN 16 THEN 'ON CONTRACT::[' + (SELECT name FROM sys.service_contracts WHERE service_contract_id = dp.major_id) + '] '
            WHEN 17 THEN 'ON SERVICE::[' + (SELECT name FROM sys.services WHERE service_id = dp.major_id) + '] '
            WHEN 18 THEN 'ON REMOTE SERVICE BINDING::[' + (SELECT name FROM sys.remote_service_bindings WHERE remote_service_binding_id = dp.major_id) + '] '
            WHEN 19 THEN 'ON ROUTE::[' + (SELECT name FROM sys.routes WHERE route_id = dp.major_id) + '] '
            WHEN 23 THEN 'ON FULLTEXT CATALOG::[' + (SELECT name FROM sys.fulltext_catalogs WHERE fulltext_catalog_id = dp.major_id) + '] '
            WHEN 24 THEN 'ON SYMMETRIC KEY::[' + (SELECT name FROM sys.symmetric_keys WHERE symmetric_key_id = dp.major_id) + '] '
            WHEN 25 THEN 'ON CERTIFICATE::[' + (SELECT name FROM sys.certificates WHERE certificate_id = dp.major_id) + '] '
            WHEN 26 THEN 'ON ASYMMETRIC KEY::[' + (SELECT name FROM sys.asymmetric_keys WHERE asymmetric_key_id = dp.major_id) + '] '
         END COLLATE SQL_Latin1_General_CP1_CI_AS
         + 'TO [' + @roleName + ']' + 
         CASE dp.state WHEN 'W' THEN ' WITH GRANT OPTION' ELSE '' END + @crlf
FROM    sys.database_permissions dp
WHERE    USER_NAME(dp.grantee_principal_id) IN (@roleName)
GROUP BY dp.state, dp.major_id, dp.permission_name, dp.class

SELECT @roleDesc = @roleDesc + 'GO' + @crlf + @crlf

-- Display users within Role.  Code stubbed by Joe Spivey
SELECT  @roleDesc = @roleDesc + 'EXECUTE sp_AddRoleMember ''' + roles.name + ''', ''' + users.name + '''' + @crlf
FROM    sys.database_principals users
        INNER JOIN sys.database_role_members link 
            ON link.member_principal_id = users.principal_id
        INNER JOIN sys.database_principals roles 
            ON roles.principal_id = link.role_principal_id
WHERE   roles.name = @roleName

-- PRINT out in blocks of up to 8000 based on last \r\n
DECLARE @printCur INT
SET @printCur = 8000

WHILE LEN(@roleDesc) > 8000
BEGIN
    -- Reverse first 8000 characters and look for first lf cr (reversed crlf) as delimiter
    SET @printCur = 8000 - CHARINDEX(CHAR(10) + CHAR(13), REVERSE(SUBSTRING(@roleDesc, 0, 8000)))

    PRINT LEFT(@roleDesc, @printCur)
    SELECT @roleDesc = RIGHT(@roleDesc, LEN(@roleDesc) - @printCur)
END

PRINT @RoleDesc + 'GO'

Il est à noter que vous pouvez rencontrer une situation où le système sp_AddRoleMember sp ajoute des utilisateurs à la base de données qui n’y figurait pas auparavant. Dans ce cas, même si le ou les utilisateurs sont ajoutés, ils ne se voient pas accorder l'autorisation CONNECT. Toute tentative de connexion effectuée par ledit utilisateur ou groupe générera une erreur de connexion de l'utilisateur. Pour résoudre ce problème, vous devez exécuter les opérations suivantes par nouvel utilisateur/groupe de la base de données:

USE [DatabaseName]
GO
GRANT CONNECT TO [Login/GroupName]
GO
3
John Eisbrener
-- Use this if you have a lot of permissions assigned to a Database Role
-- Before running, set results to Text

SET NOCOUNT ON

Use MyDB;  -- CHANGE DATABASE NAME

DECLARE @RoleName varchar(50) = 'sp_exec' --- change role name here

SELECT 'CREATE ROLE [' + @RoleName + '];'+ char(13)

SELECT  'GRANT ' + prm.permission_name + ' ON [' + 
OBJECT_NAME(major_id) + '] TO [' + rol.name + '] ;' + char(13) COLLATE Latin1_General_CI_AS

from sys.database_permissions prm

    join sys.database_principals rol on

        prm.grantee_principal_id = rol.principal_id

where rol.name = @RoleName
0
MudassiR ShaikH

C'est difficile, mais tout ce que vous recherchez se trouve dans deux vues système: sys.database_permissions, sys.database_principals et sys.database_role_members. La raison pour laquelle il ne s'agit pas d'une friandise est que major_id et minor_id dans sys.database_permissions ont des significations différentes en fonction de la colonne de classe. Mais si vos autorisations sont relativement simples, cela pourrait ne pas être si grave. Jetez un coup d'oeil et voyez ce que vous pouvez obtenir.

0
Ben Thul