在 SQL Server 實例之間傳輸登入和密碼

本文說明如何在 Windows 上執行的不同 SQL Server 實例之間傳輸登入和密碼。

原始產品版本:   Sqlserver
原始 KB 編號:   918992

簡介

本文說明如何在 Microsoft SQL Server 的不同實例之間傳輸登入和密碼。

注意

實例可能位於同一部伺服器或不同的伺服器上,而且其版本可能不同。

詳細資訊

在本文中,伺服器 A 和伺服器 B 是不同的伺服器。

將資料庫從伺服器 A 上的 SQL Server 實例移至伺服器 B 上的 SQL Server 實例之後,使用者可能無法登入伺服器 B 上的資料庫。此外,使用者可能會收到下列錯誤訊息:

使用者 'MyUser' 登入失敗。 (Microsoft SQL Server,錯誤: 18456)

發生此問題是因為您未將伺服器 A 上的 SQL Server 實例的登入和密碼傳送至伺服器 B 上的 SQL Server 實例。

注意

因為其他原因,所以也會發生 18456-錯誤訊息。 如需這些原因及可能的解決方法的詳細資訊,請 MSSQLSERVER_18456

若要傳輸登入,請根據您的情況,使用下列其中一種方法。

  • 方法1:在目的 SQL Server 電腦上重設密碼 (Server B)

    若要解決此問題,請重設 SQL Server 電腦的密碼,然後以腳本編寫登入。

    注意

    當您重設密碼時,會使用密碼雜湊演算法。

  • 方法2:使用源伺服器上所產生的腳本,將登入和密碼傳送至目的伺服器 (伺服器 A) (伺服器 A)

    1. 建立可協助產生必要腳本以傳輸登入及其密碼的預存程式。 若要這麼做,請使用 SQL Server Management Studio (SSMS) 或任何其他用戶端工具連線到伺服器 A,並執行下列腳本:

      USE master
      GO
      IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
      DROP PROCEDURE sp_hexadecimal
      GO
      CREATE PROCEDURE sp_hexadecimal
      @binvalue varbinary(256),
      @hexvalue varchar (514) OUTPUT
      AS
      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
      GO
      
      IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
      DROP PROCEDURE sp_help_revlogin
      GO
      CREATE PROCEDURE sp_help_revlogin @login_name sysname = NULL AS
      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 @defaultdb sysname
      
      IF (@login_name IS NULL)
      DECLARE login_curs CURSOR FOR
      
      SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin 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'
      ELSE
      DECLARE login_curs CURSOR FOR
      
      SELECT p.sid, p.name, p.type, p.is_disabled, p.default_database_name, l.hasaccess, l.denylogin 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
      OPEN login_curs
      
      FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
      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
      IF (@type IN ( 'G', 'U'))
      BEGIN -- NT authenticated account/group
      
      SET @tmpstr = 'CREATE LOGIN ' + QUOTENAME( @name ) + ' FROM WINDOWS WITH DEFAULT_DATABASE = [' + @defaultdb + ']'
      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 + ']'
      
      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
      PRINT @tmpstr
      END
      
      FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @hasaccess, @denylogin
      END
      CLOSE login_curs
      DEALLOCATE login_curs
      RETURN 0
      GO
      

      注意

      此腳本會在 master 資料庫中建立兩個預存程式。 程式命名為 sp_hexadecimalsp_help_revlogin

    2. 在 SSMS 查詢編輯器中,選取 [ 結果到文字 ] 選項。

    3. 在相同或新的查詢視窗中執行下列語句:

      EXEC sp_help_revlogin
      
    4. 預存程式所產生的輸出腳本 sp_help_revlogin 為登入腳本。 此登入腳本會建立具有原始安全性識別碼 (SID) 和原始密碼的登入。

重要

請先複查下列 [ 備註 ] 區段中的資訊,再繼續執行目的伺服器上的步驟。

目的伺服器上的步驟 (Server B)

使用任何用戶端工具 ((如 SSMS) )連線至伺服器 B,然後執行在步驟4中產生的腳本, (sp_helprevlogin 從伺服器 A) 輸出。

註解

在伺服器 B 上的實例上執行輸出腳本之前,請先複查下列資訊:

  • 您可以使用下列方式來雜湊密碼:

    • VERSION_SHA1:此雜湊是使用 SHA1 演算法產生,並透過 SQL Server 2008 R2 使用於 SQL Server 2000。
    • VERSION_SHA2:此雜湊是以 SHA2 512 演算法產生,在 SQL Server 2012 和更新版本中使用。
  • 仔細檢查輸出腳本。 如果伺服器 A 和伺服器 B 位於不同的網域,您必須變更輸出腳本。 然後,您必須使用 CREATE LOGIN 語句中的新功能變數名稱取代原始的功能變數名稱。 在新網域中授與存取權的整合登入,與原始網域中的登入沒有相同的 SID。 因此,使用者會從這些登入中孤立。 如需如何解決這些孤立使用者的詳細資訊,請參閱 how to:在 執行 SQL Server 的伺服器之間移動資料庫時,如何解決許可權問題

    如果伺服器 A 與伺服器 B 位於相同的網域,則會使用相同的 SID。 因此,使用者不太可能是孤立的。

  • 在輸出腳本中,使用加密的密碼來建立登入。 這是因為語句中的雜湊引數 CREATE LOGIN 。 此引數會指定已雜湊密碼引數之後所輸入的密碼。

  • 根據預設,只有 sysadmin 固定伺服器角色的成員才能 SELECT 從 view 執行語句 sys.server_principals 。 除非 sysadmin 固定伺服器角色的成員授與使用者的必要許可權,否則使用者無法建立或執行輸出腳本。

  • 本文中的步驟不會傳輸特定登入的預設資料庫資訊。 這是因為預設資料庫可能不一定會存在於伺服器 B 上。若要定義登入的預設資料庫,請透過 ALTER LOGIN 傳入登入名稱和預設資料庫做為引數來使用語句。

  • 在來源伺服器和目的伺服器上排序次序:

    • 區分大小寫的伺服器 a 和區分大小寫的伺服器 b:伺服器 a 的排序次序可能不區分大小寫,而伺服器 B 的排序次序可能會區分大小寫。 在此情況下,當您將登入和密碼傳送至伺服器 B 上的實例之後,使用者必須在所有大寫字母中輸入密碼。

    • 區分 大小寫的伺服器 a 和不區分大小寫的伺服器 B: 伺服器 A 的排序次序可能會區分大小寫,而伺服器 B 的排序次序則可能不區分大小寫。 在此情況下,除非下列其中一個條件為真,否則使用者無法使用傳送至伺服器 B 之實例的登入和密碼登入:

      • 原始密碼不含任何字母。
      • 原始密碼中的所有字母都是大寫字母。
    • 在兩部伺服器上 都有區分大小寫或不區分大小寫:伺服器 a 與伺服器 b 的排序次序都可能是區分大小寫的,或是伺服器 a 和伺服器 b 的排序次序都可能不區分大小寫。 在這些情況下,使用者不會遇到問題。

  • 已在伺服器 B 上的實例中登入的名稱,可能會具有與輸出腳本中的名稱相同的名稱。 在此情況下,當您在伺服器 B 上的實例上執行輸出腳本時,會收到下列錯誤訊息:

    Msg 15025,Level 16,State 1,第1列
    伺服器主體 'MyLogin' 已存在。

    同樣地,已在伺服器 B 上的實例中的登入,其 SID 會與輸出腳本中的 SID 相同。 在此情況下,當您在伺服器 B 上的實例上執行輸出腳本時,會收到下列錯誤訊息:

    Msg 15433,Level 16,State 1,已使用第1列的參數 sid 正在使用中。

    因此,您必須執行下列作業:

    1. 仔細檢查輸出腳本。

    2. 檢查伺服器 B 實例中 sys.server_principals view 的內容。

    3. 適當地處理這些錯誤訊息。

      在 SQL Server 2005 中,登入的 SID 是用來執行資料庫層級存取。 在伺服器上,登入的不同資料庫可能會有不同的 Sid。 在此情況下,登入只會存取其 SID 與視圖中的 SID 相符的資料庫 sys.server_principals 。 如果這兩個資料庫組合在不同的伺服器上,可能會發生此問題。 若要解決此問題,請使用 DROP USER 語句,手動移除具有 SID 不符之資料庫中的登入。 然後,使用語句再次加入登入 CREATE USER

參考