Передача имен входа и паролей между экземплярами SQL Server

В этой статье описывается, как передавать имена входа и пароли между различными экземплярами SQL Server под управлением Windows.

Оригинальная версия продукта: SQL Server
Оригинальный номер базы знаний: 918992, 246133

Введение

В этой статье описывается способ передачи имен входа и паролей между различными экземплярами Microsoft SQL Server.

Примечание.

Экземпляры могут находиться на одном сервере или на разных серверах, и их версии могут отличаться.

Дополнительные сведения

В этой статье сервер A и сервер B являются разными серверами.

После перемещения базы данных с экземпляра SQL Server на сервере A в экземпляр SQL Server на сервере B пользователи могут не входить в базу данных на сервере B. Кроме того, пользователи могут получить следующее сообщение об ошибке:

Сбой входа для пользователя "MyUser". (Microsoft SQL Server, ошибка: 18456)

Эта проблема возникает из-за того, что вы не передали имена входа и пароли из экземпляра SQL Server на сервере A в экземпляр SQL Server на сервере B.

Примечание.

Сообщение об ошибке 18456 также возникает по другим причинам. Дополнительные сведения об этих причинах и возможных решениях см. в разделе MSSQLSERVER_18456.

Чтобы передать имена входа, воспользуйтесь одним из описанных ниже способов в зависимости от ситуации.

  • Способ 1. Сброс пароля на целевом SQL Server компьютере (сервер B).

    Чтобы устранить эту проблему, сбросьте пароль на компьютере SQL Server, а затем выполните сценарий входа.

    Примечание.

    Алгоритм хэширования паролей используется при сбросе пароля.

  • Метод 2. Передача имен входа и паролей на целевой сервер (сервер B) с помощью скриптов, созданных на исходном сервере (сервер A).

    1. Создайте хранимые процедуры, которые помогут создать необходимые сценарии для передачи имен входа и паролей. Для этого подключитесь к серверу A с помощью SQL Server Management Studio (SSMS) или любого другого клиентского средства и запустите следующий сценарий:

        USE [master]
        GO
        IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
        DROP PROCEDURE sp_hexadecimal
        GO
        CREATE PROCEDURE [dbo].[sp_hexadecimal]
        (
            @binvalue varbinary(256),
            @hexvalue varchar (514) OUTPUT
        )
        AS
        BEGIN
            DECLARE @charvalue varchar (514)
            DECLARE @i int
            DECLARE @length int
            DECLARE @hexstring char(16)
            SELECT @charvalue = '0x'
            SELECT @i = 1
            SELECT @length = DATALENGTH (@binvalue)
            SELECT @hexstring = '0123456789ABCDEF'
      
            WHILE (@i <= @length)
            BEGIN
                  DECLARE @tempint int
                  DECLARE @firstint int
                  DECLARE @secondint int
      
                  SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
                  SELECT @firstint = FLOOR(@tempint/16)
                  SELECT @secondint = @tempint - (@firstint*16)
                  SELECT @charvalue = @charvalue + SUBSTRING(@hexstring, @firstint+1, 1) + SUBSTRING(@hexstring, @secondint+1, 1)
      
                  SELECT @i = @i + 1
            END 
            SELECT @hexvalue = @charvalue
        END
        go
        IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
        DROP PROCEDURE sp_help_revlogin
        GO
        CREATE PROCEDURE [dbo].[sp_help_revlogin]   
        (
            @login_name sysname = NULL 
        )
        AS
        BEGIN
            DECLARE @name                     SYSNAME
            DECLARE @type                     VARCHAR (1)
            DECLARE @hasaccess                INT
            DECLARE @denylogin                INT
            DECLARE @is_disabled              INT
            DECLARE @PWD_varbinary            VARBINARY (256)
            DECLARE @PWD_string               VARCHAR (514)
            DECLARE @SID_varbinary            VARBINARY (85)
            DECLARE @SID_string               VARCHAR (514)
            DECLARE @tmpstr                   VARCHAR (1024)
            DECLARE @is_policy_checked        VARCHAR (3)
            DECLARE @is_expiration_checked    VARCHAR (3)
            Declare @Prefix                   VARCHAR(255)
            DECLARE @defaultdb                SYSNAME
            DECLARE @defaultlanguage          SYSNAME     
            DECLARE @tmpstrRole               VARCHAR (1024)
      
        IF (@login_name IS NULL)
        BEGIN
            DECLARE login_curs CURSOR 
            FOR 
                SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin, p.default_language_name  
                FROM  sys.server_principals p 
                LEFT JOIN sys.syslogins     l ON ( l.name = p.name ) 
                WHERE p.type IN ( 'S', 'G', 'U' ) 
                AND p.name <> 'sa'
                AND p.name not like '##%'
                ORDER BY p.name
        END
        ELSE
                DECLARE login_curs CURSOR 
                FOR 
                    SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin, p.default_language_name  
                    FROM  sys.server_principals p 
                    LEFT JOIN sys.syslogins        l ON ( l.name = p.name ) 
                    WHERE p.type IN ( 'S', 'G', 'U' ) 
                      AND p.name = @login_name
                    ORDER BY p.name
      
                OPEN login_curs 
                FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin, @defaultlanguage 
                IF (@@fetch_status = -1)
                BEGIN
                      PRINT 'No login(s) found.'
                      CLOSE login_curs
                      DEALLOCATE login_curs
                      RETURN -1
                END
      
                SET @tmpstr = '/* sp_help_revlogin script '
                PRINT @tmpstr
      
                SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */'
      
                PRINT @tmpstr
                PRINT ''
      
                WHILE (@@fetch_status <> -1)
                BEGIN
                  IF (@@fetch_status <> -2)
                  BEGIN
                        PRINT ''
      
                        SET @tmpstr = '-- Login: ' + @name
      
                        PRINT @tmpstr
      
                        SET @tmpstr='IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = N'''+@name+''')
                        BEGIN'
                        Print @tmpstr 
      
                        IF (@type IN ( 'G', 'U'))
                        BEGIN -- NT authenticated account/group 
                          SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @defaultdb + ']' + ', DEFAULT_LANGUAGE = [' + @defaultlanguage + ']'
                        END
                        ELSE 
                        BEGIN -- SQL Server authentication
                                -- obtain password and sid
                                SET @PWD_varbinary = CAST( LOGINPROPERTY( @name, 'PasswordHash' ) AS varbinary (256) )
      
                                EXEC sp_hexadecimal @PWD_varbinary, @PWD_string OUT
                                EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT
      
                                -- obtain password policy state
                                SELECT @is_policy_checked     = CASE is_policy_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END 
                                FROM sys.sql_logins 
                                WHERE name = @name
      
                                SELECT @is_expiration_checked = CASE is_expiration_checked WHEN 1 THEN 'ON' WHEN 0 THEN 'OFF' ELSE NULL END 
                                FROM sys.sql_logins 
                                WHERE name = @name
      
                                SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' WITH PASSWORD = ' + @PWD_string + ' HASHED, SID = ' 
                                                + @SID_string + ', DEFAULT_DATABASE = [' + @defaultdb + ']' + ', DEFAULT_LANGUAGE = [' + @defaultlanguage + ']'
      
                                IF ( @is_policy_checked IS NOT NULL )
                                BEGIN
                                  SET @tmpstr = @tmpstr + ', CHECK_POLICY = ' + @is_policy_checked
                                END
      
                                IF ( @is_expiration_checked IS NOT NULL )
                                BEGIN
                                  SET @tmpstr = @tmpstr + ', CHECK_EXPIRATION = ' + @is_expiration_checked
                                END
                END
      
                IF (@denylogin = 1)
                BEGIN -- login is denied access
                    SET @tmpstr = @tmpstr + '; DENY CONNECT SQL TO ' + QUOTENAME( @name )
                END
                ELSE IF (@hasaccess = 0)
                BEGIN -- login exists but does not have access
                    SET @tmpstr = @tmpstr + '; REVOKE CONNECT SQL TO ' + QUOTENAME( @name )
                END
                IF (@is_disabled = 1)
                BEGIN -- login is disabled
                    SET @tmpstr = @tmpstr + '; ALTER LOGIN ' + QUOTENAME( @name ) + ' DISABLE'
                END 
      
                SET @Prefix = '
                EXEC master.dbo.sp_addsrvrolemember @loginame='''
      
                SET @tmpstrRole=''
      
                SELECT @tmpstrRole = @tmpstrRole
                    + CASE WHEN sysadmin        = 1 THEN @Prefix + [LoginName] + ''', @rolename=''sysadmin'''        ELSE '' END
                    + CASE WHEN securityadmin   = 1 THEN @Prefix + [LoginName] + ''', @rolename=''securityadmin'''   ELSE '' END
                    + CASE WHEN serveradmin     = 1 THEN @Prefix + [LoginName] + ''', @rolename=''serveradmin'''     ELSE '' END
                    + CASE WHEN setupadmin      = 1 THEN @Prefix + [LoginName] + ''', @rolename=''setupadmin'''      ELSE '' END
                    + CASE WHEN processadmin    = 1 THEN @Prefix + [LoginName] + ''', @rolename=''processadmin'''    ELSE '' END
                    + CASE WHEN diskadmin       = 1 THEN @Prefix + [LoginName] + ''', @rolename=''diskadmin'''       ELSE '' END
                    + CASE WHEN dbcreator       = 1 THEN @Prefix + [LoginName] + ''', @rolename=''dbcreator'''       ELSE '' END
                    + CASE WHEN bulkadmin       = 1 THEN @Prefix + [LoginName] + ''', @rolename=''bulkadmin'''       ELSE '' END
                  FROM (
                            SELECT CONVERT(VARCHAR(100),SUSER_SNAME(sid)) AS [LoginName],
                                    sysadmin,
                                    securityadmin,
                                    serveradmin,
                                    setupadmin,
                                    processadmin,
                                    diskadmin,
                                    dbcreator,
                                    bulkadmin
                            FROM sys.syslogins
                            WHERE (       sysadmin<>0
                                    OR    securityadmin<>0
                                    OR    serveradmin<>0
                                    OR    setupadmin <>0
                                    OR    processadmin <>0
                                    OR    diskadmin<>0
                                    OR    dbcreator<>0
                                    OR    bulkadmin<>0
                                ) 
                                AND name=@name 
                      ) L 
      
                    PRINT @tmpstr
                    PRINT @tmpstrRole
                    PRINT 'END'
                END 
                FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin, @defaultlanguage 
            END
            CLOSE login_curs
            DEALLOCATE login_curs
            RETURN 0
        END
      

      Примечание.

      Этот сценарий создает две хранимые процедуры в главной базе данных. Процедуры называются sp_hexadecimal и sp_help_revlogin.

    2. В редакторе запросов SSMS выберите параметр Результаты в текст.

    3. Выполните следующую инструкцию в том же или новом окне запроса:

      EXEC sp_help_revlogin
      
    4. Сценарий вывода, который создает хранимая процедура sp_help_revlogin, является сценарием входа. Этот сценарий входа создает имена входа с исходным идентификатором безопасности (SID) и исходным паролем.

Важно!

Ознакомьтесь со сведениями в следующем разделе Примечания, прежде чем приступить к реализации действий на целевом сервере.

Действия на целевом сервере (сервер B)

Подключитесь к серверу B с помощью любого клиентского средства (например, SSMS), а затем запустите скрипт, созданный на шаге 4 (выходные sp_helprevloginданные ) на сервере A.

Замечания

Перед запуском сценария вывода на экземпляре на сервере B просмотрите следующие сведения:

  • Хэширование пароля может выполняться следующими способами:

    • VERSION_SHA1: этот хэш создается с помощью алгоритма SHA1 и используется в SQL Server, начиная с версии от 2000 до 2008 R2.
    • VERSION_SHA2: этот хэш создается с помощью алгоритма SHA2 512 и используется в SQL Server 2012 и более поздних версиях.
  • Внимательно просмотрите сценарий вывода. Если сервер A и сервер B находятся в разных доменах, необходимо изменить сценарий вывода. Затем необходимо заменить исходное доменное имя новым доменным именем в CREATE LOGIN инструкциях . Интегрированные имена входа, которым предоставлен доступ в новом домене, не имеют тот же идентификатор безопасности, что и имена входа в исходном домене. Таким образом, пользователи будут потеряны из-за этих имен входа. Дополнительные сведения о том, как устранить проблему с этими потерянными пользователями, см. в разделах Устранение неполадок потерянных пользователей (SQL Server) и ALTER USER.
    Если сервер A и сервер B находятся в одном домене, используется один и тот же идентификатор безопасности. Поэтому пользователи вряд ли будут потеряны.

  • В сценарии вывода имена входа создаются с помощью зашифрованного пароля. Это связано с аргументом HASHED в инструкции CREATE LOGIN. Этот аргумент указывает, что пароль, введенный после аргумента PASSWORD, уже хэширован.

  • По умолчанию только член предопределенной роли сервера sysadmin может выполнять инструкцию SELECT из представления sys.server_principals. Если член предопределенной роли сервера sysadmin не предоставляет пользователям необходимые разрешения, пользователи не смогут создать или запустить выходной скрипт.

  • Действия, описанные в этой статье, не передают сведения о базе данных по умолчанию для определенного имени входа. Это связано с тем, что база данных по умолчанию может существовать не всегда на сервере B. Чтобы определить базу данных по умолчанию для имени входа, используйте инструкцию ALTER LOGIN , передав имя входа и базу данных по умолчанию в качестве аргументов.

  • Порядок сортировки на исходном и целевом серверах:

    • Сервер A без учета регистра и сервер B с учетом регистра. Порядок сортировки сервера A может быть без учета регистра, а порядок сортировки сервера B может быть с учетом регистра. В этом случае пользователи должны ввести пароли заглавными буквами после передачи имен входа и паролей экземпляру на сервере B.

    • Сервер A с учетом регистра и сервер B без учета регистра: Порядок сортировки сервера A может учитывать регистр, а порядок сортировки сервера B — без учета регистра. В этом случае пользователи не могут войти в систему с помощью имен входа и паролей, передаваемых экземпляру на сервере B, если не выполняется одно из следующих условий:

      • Исходные пароли не содержат букв.
      • Исходные пароли содержат только прописные буквы.
    • С учетом регистра или без учета регистра на обоих серверах. Порядок сортировки сервера A и сервера B может быть с учетом регистра, или порядок сортировки сервера A и сервера B может быть без учета регистра. В таких случаях у пользователей нет проблем.

  • Имя входа, которое уже находится в экземпляре на сервере B, может иметь имя, совпадающее с именем в выходном скрипте. В этом случае при запуске сценария вывода на экземпляре на сервере B отобразится следующее сообщение об ошибке:

    Сообщение 15025, уровень 16, состояние 1, строка 1
    Субъект-сервер "MyLogin" уже существует.

    Аналогичным образом имя входа, которое уже находится в экземпляре на сервере B, может иметь идентификатор безопасности, аналогичный идентификатору безопасности в выходном скрипте. В этом случае при запуске сценария вывода на экземпляре на сервере B отобразится следующее сообщение об ошибке:

    Сообщение 15433, уровень 16, состояние 1, строка 1, «Предоставленный параметр для идентификатора безопасности уже используется».

    Для этого необходимо выполнить следующие действия:

    1. Внимательно просмотрите сценарий вывода.

    2. Изучите содержимое sys.server_principals представления в экземпляре на сервере B.

    3. Устраните эти сообщения об ошибках соответствующим образом.

      В SQL Server 2005 для реализации доступа на уровне базы данных используется идентификатор безопасности для имени входа. Имя входа может иметь разные идентификаторы БЕЗОПАСНОСТИ в разных базах данных на сервере. В этом случае имя входа может получить доступ только к базе данных с идентификатором безопасности, который соответствует идентификатору безопасности в представлении sys.server_principals. Эта проблема может возникнуть, если две базы данных объединены с разных серверов. Чтобы устранить эту проблему, вручную удалите имя входа из базы данных с несоответствием идентификатора безопасности с помощью инструкции DROP USER. Затем снова добавьте имя входа с помощью инструкции CREATE USER.

Ссылки