2009-05-15 7 views
39

Desidero spostare un database tra due server, ho eseguito il backup del database dal primo server e completato il ripristino del database sul secondo server, finora tutto bene.Collegamento degli utenti al login dopo il ripristino di un database SQL Server 2005

Tuttavia, la nostra applicazione utilizza molti utenti del database definiti nel database. Questi devono essere collegati agli accessi che sono definiti nel database principale. Il server su cui ho ripristinato il database ha tutti gli accessi definiti, tuttavia hanno sids diversi.

Non sono un esperto T-SQL ....

penso sp_change_users_login fa parte della soluzione, ma non riesco a trovare il modo di arrivare a collegare automaticamente tutti utenti nel database ripristinato l'accesso con lo stesso nome.

Gli script di creazione del database che utilizziamo per la nostra applicazione creano utenti e accessi, tuttavia non specifica il SID durante la creazione dell'accesso, quindi questo problema. Ora se avessi una macchina del tempo ...

(Quando ho Google ottengo un sacco di visite, tuttavia sono per lo più siti che non ti permettono di vedere la risposta senza dover prima registrarti sul sito.)

+0

Vedi anche questa domanda http://stackoverflow.com/questions/229883/sync-sql-login-utility-on-2005-2008 – Cruachan

risposta

28

Questo fenomeno è chiamato "utenti orfani".

Ecco un articolo su di esso e come risolvere il problema:

http://sqlblog.com/blogs/eric_johnson/archive/2008/10/17/fixing-orphaned-users.aspx

Ed ecco l'articolo documentazione in linea sul comando:

http://msdn.microsoft.com/en-us/library/aa259633(SQL.80).aspx

+1

Questo metodo è in realtà deprecato da SQL Server 2008: http://msdn.microsoft.com/en-us/library/ms143729(v=sql.100).aspx. Utilizzare invece ALTER USER. –

+2

Per informazioni, la sintassi di alter è ... ALTER USER WITH LOGIN = pperrin

+0

Abbiamo rilevato che in SQL2014 questo passaggio non è più necessario. Dopo aver ripristinato un database, gli accessi vengono automaticamente ricollegati agli utenti. – Mike

1

Ho trovato il seguente script da Microsoft KB918992 - lo eseguo sul server originale e creerà una stored procedure chiamata "sp_help_revlogin" che genera un altro script da eseguire sul server di destinazione, creando tutti gli account utente con le stesse password e sids. Fatto miracoli per il nostro aggiornamento da SQL2000 al 2008.

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(256) OUTPUT 
AS 
DECLARE @charvalue varchar(256) 
DECLARE @i int 
DECLARE @length int 
DECLARE @hexstring char(16) 
SELECT @charvalue = '0x' 
SELECT @i = 1 
SELECT @length = DATALENGTH (@binvalue) 
SELECT @hexstring = 'ABCDEF' 
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 @xstatus int 
DECLARE @binpwd varbinary (256) 
DECLARE @txtpwd sysname 
DECLARE @tmpstr varchar (256) 
DECLARE @SID_varbinary varbinary(85) 
DECLARE @SID_string varchar(256) 

IF (@login_name IS NULL) 
    DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name <> 'sa' 
ELSE 
    DECLARE login_curs CURSOR FOR 
    SELECT sid, name, xstatus, password FROM master..sysxlogins 
    WHERE srvid IS NULL AND name = @login_name 
OPEN login_curs 
FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd 
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 '' 
PRINT 'DECLARE @pwd sysname' 
WHILE (@@fetch_status <> -1) 
BEGIN 
    IF (@@fetch_status <> -2) 
    BEGIN 
    PRINT '' 
    SET @tmpstr = '-- Login: ' + @name 
    PRINT @tmpstr 
    IF (@xstatus & 4) = 4 
    BEGIN -- NT authenticated account/group 
     IF (@xstatus & 1) = 1 
     BEGIN -- NT login is denied access 
     SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + '''' 
     PRINT @tmpstr 
     END 
     ELSE BEGIN -- NT login has access 
     SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + '''' 
     PRINT @tmpstr 
     END 
    END 
    ELSE BEGIN -- SQL Server authentication 
     IF (@binpwd IS NOT NULL) 
     BEGIN -- Non-null password 
     EXEC sp_hexadecimal @binpwd, @txtpwd OUT 
     IF (@xstatus & 2048) = 2048 
      SET @tmpstr = 'SET @pwd = CONVERT (varchar(256), ' + @txtpwd + ')' 
     ELSE 
      SET @tmpstr = 'SET @pwd = CONVERT (varbinary(256), ' + @txtpwd + ')' 
     PRINT @tmpstr 
    EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT 
     SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
      + ''', @pwd, @sid = ' + @SID_string + ', @encryptopt = ' 
     END 
     ELSE BEGIN 
     -- Null password 
    EXEC sp_hexadecimal @SID_varbinary,@SID_string OUT 
     SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name 
      + ''', NULL, @sid = ' + @SID_string + ', @encryptopt = ' 
     END 
     IF (@xstatus & 2048) = 2048 
     -- login upgraded from 6.5 
     SET @tmpstr = @tmpstr + '''skip_encryption_old''' 
     ELSE 
     SET @tmpstr = @tmpstr + '''skip_encryption''' 
     PRINT @tmpstr 
    END 
    END 
    FETCH NEXT FROM login_curs INTO @SID_varbinary, @name, @xstatus, @binpwd 
    END 
CLOSE login_curs 
DEALLOCATE login_curs 
RETURN 0 
GO 
+0

Il server di destinazione dispone già di tutti gli accessi creati, tuttavia grazie per aver postato th e script sarà utile ad altre persone –

+0

Questa procedura è anche buona perché conserva il SID dell'account di accesso di SQL Server in modo che vengano creati uguali sul server di destinazione. Molto utile in scenari come la spedizione dei log. –

37

Sì, è possibile farlo eseguendo:

EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName'; 

Tuttavia, se la tua domanda era posso risolvere tutti gli utenti automaticamente, allora questo non farà quella.

1

ho un bel script che è possibile utilizzare per creare accessi dagli utenti del database, che ho trovato dopo aver cercato questo problema, questo script sta utilizzando una stored procedure. si possono trovare alcuni altri script utili anche qui a questo indirizzo http://www.sqlserveroptimizer.com/2011/08/how-to-script-logins-from-user-database-in-sql-server-20052008-r2/

USE MyDatabaseName 

DECLARE @login nvarchar(50) 

DECLARE logins_cursor CURSOR FOR SELECT l.name FROM sys.database_principals u INNER JOIN sys.server_principals l ON u.sid=l.sid 

OPEN logins_cursor FETCH NEXT FROM logins_cursor INTO @login 

WHILE @@FETCH_STATUS = 0 BEGIN EXEC sp_help_revlogin @login FETCH NEXT FROM logins_cursor INTO @login END 

CLOSE logins_cursor DEALLOCATE logins_cursor GO 
25

mi si avvicinò con il seguente. Funziona benissimo perché ti mostra:

  1. Tutti gli utenti orfani attuali.
  2. Quali sono stati corretti.
  3. Quali non è stato possibile correggere.

Altre soluzioni richiedono di conoscere in anticipo il nome utente orfano per la correzione.

Il seguente codice potrebbe essere eseguito in un file chiamato dopo il ripristino di un database su un altro server.

Script:

EXEC sp_change_users_login 'report'--See all orphaned users in the database. 
DECLARE @OrphanedUsers TABLE 
(
    IndexKey Int IDENTITY(1,1) PRIMARY KEY, 
    UserName SysName,--nVarChar(128) 
    UserSID VarBinary(85) 
) 
INSERT INTO @OrphanedUsers 
    EXEC sp_change_users_login 'report' 

DECLARE @CRLF as nVarChar 
    SET @CRLF = CHAR(10) + '&' + CHAR(13)--NOTE: Carriage-Return/Line-Feed will only appear in PRINT statements, not SELECT statements. 
DECLARE @Sql as nVarChar(MAX) 
    SET @Sql = N'' 
DECLARE @IndexKey as Int 
    SET @IndexKey = 1 
DECLARE @MaxIndexKey as Int 
    SET @MaxIndexKey = (SELECT COUNT(*) FROM @OrphanedUsers) 
DECLARE @Count as Int 
    SET @Count = 0 
DECLARE @UsersFixed as nVarChar(MAX) 
    SET @UsersFixed = N'' 
DECLARE @UserName as SysName--This is an orphaned Database user. 

WHILE (@IndexKey <= @MaxIndexKey) 
    BEGIN 
    SET @UserName = (SELECT UserName FROM @OrphanedUsers WHERE IndexKey = @IndexKey) 
    IF 1 = (SELECT COUNT(*) FROM sys.server_principals WHERE Name = @UserName)--Look for a match in the Server Logins. 
     BEGIN 
     SET @Sql = @Sql + 'EXEC sp_change_users_login ''update_one'', [' + @UserName + '], [' + @UserName + ']' + @CRLF 
     SET @UsersFixed = @UsersFixed + @UserName + ', ' 
     SET @Count = @Count + 1 
     END 
    SET @IndexKey = @IndexKey + 1 
    END 

PRINT @Sql 
EXEC sp_executesql @Sql 
PRINT 'Total fixed: ' + CAST(@Count as VarChar) + '. Users Fixed: ' + @UsersFixed 
SELECT ('Total fixed: ' + CAST(@Count as VarChar) + '. Users Fixed: ' + @UsersFixed)[Fixed] 
EXEC sp_change_users_login 'report'--See all orphaned users still in the database. 

Risultato:

enter image description here

* Nota: il 4 che non sono stati fissati (nel mio esempio screenshot sopra) non ebbe un corrispondente utente nel server di destinazione in cui è stato ripristinato il database.

+3

Amico, è fantastico! Molto bene. – CrazyTim

+2

Questo ha funzionato benissimo per me, fatta eccezione per una manciata di utenti (e gli accessi di corrispondenza da cui erano rimasti orfani) che avevano citazioni singole nel loro nome (sono rimasto sorpreso che fossero addirittura legali!). Ho cambiato i parametri passati a sp_change_users_login qui per passare [nome utente] invece di "nome utente" e poi anche quegli utenti hanno funzionato (e anche quelli "normali" sono stati corretti correttamente dopo tale modifica.) Grazie, @MikeTeeVee per un grande script! –

+0

Sarebbe uno sforzo incredibile da parte di un utente malintenzionato e probabilmente non vale la pena di essere guardato, ma come avvertimento comunque: "']; utenti Drop table;" è un nome utente SQL valido che potrebbe essere usato per il male. Edit: presumibilmente il DBA sarebbe l'ho rilevato, ma ho visto abbastanza app che consentono agli utenti di creare il proprio nome utente DB. – Squid

Problemi correlati