2009-05-15 7 views
39

두 서버간에 데이터베이스를 이동하려는 경우 첫 번째 서버에서 데이터베이스를 백업하고 두 번째 서버에서 데이터베이스 복원을 완료했습니다.SQL Server 2005 데이터베이스를 복원 한 후 사용자를 로그인에 연결

그러나 Google 애플리케이션은 데이터베이스에 정의 된 많은 데이터베이스 사용자를 사용합니다. 마스터 데이터베이스에 정의 된 로그인에 연결해야합니다. 데이터베이스를 복원 한 서버에는 정의 된 모든 로그인이 있지만 서로 다른 sids가 있습니다.

저는 T-SQL 전문가가 아닙니다 ....

나는 sp_change_users_login이 해결책의 일부라고 생각하지만, 명의 사용자가 같은 이름의 로그인으로 복원 된 데이터베이스에 자동으로 연결되도록하는 방법을 찾을 수 없습니다.

우리가 응용 프로그램에 사용하는 데이터베이스 작성 스크립트는 사용자 및 로그인을 만들지 만 로그인을 만들 때 SID를 지정하지 않으므로이 문제가 발생합니다. 이제 내가 타임머신을 가지고 있다면 ...

(나는 많은 히트작을 얻었지만 대부분이 사이트에 등록 할 필요없이 대답을 볼 수없는 사이트입니다.)

+0

참조 또한이 질문에 http://stackoverflow.com/questions/229883/sync-sql-logins-utility-on-2005-2008 – Cruachan

답변

28

이 현상을 "고아 사용자"라고합니다. 여기

가에 대한 기사이고 그것을 해결하는 방법 :

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

을 그리고 여기에 명령에 대한 온라인 기사입니다 : http://msdn.microsoft.com/en-us/library/aa259633(SQL.80).aspx

+1

이 메서드는 실제로 SQL Server 2008에서 더 이상 사용되지 않습니다. http://msdn.microsoft.com/en-us/library/ms143729(v=sql.100).aspx. 대신 ALTER USER를 사용하십시오. –

+2

정보를 얻으려면 alter에 대한 구문은 ... 변경자 WITH LOGIN = pperrin

+0

SQL2014에서이 단계는 더 이상 필요하지 않습니다. 데이터베이스를 복원 한 후 로그인은 자동으로 사용자와 다시 연결됩니다. – Mike

1

Microsoft KB918992에서 다음 스크립트를 찾았습니다. 원래 서버에서 실행하면 'sp_help_revlogin'이라는 저장 프로 시저가 생성되어 대상 서버에서 실행될 다른 스크립트를 생성하여 동일한 암호와 sid를 가진 모든 사용자 계정을 만듭니다. 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

대상 서버에는 이미 모든 로그인이 생성되어 있지만 게시 해 주셔서 감사합니다. 전자 메일이 유용 할 것입니다. –

+0

이 절차는 SQL Server 로그인의 SID가 보존되어 대상 서버에서 동일하게 만들어지기 때문에 좋습니다. 로그 전달과 같은 시나리오에서 매우 유용합니다. –

37

예에 SQL2000에서 우리의 업그레이드에 대한 경이로움을 일했다, 당신은에 의해 실행하는 것을 수행 할 수 있습니다 질문이 있다면

EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName'; 

그러나 나는 자동으로 모든 사용자를 해결할 수 이것은하지 않을 것이다 그.

1

는 내가 좋은 스크립트가 그 당신은 데이터베이스 사용자로부터 로그인을 생성하는데 사용할 수 있습니다.이 스크립트는 저장 프로 시저를 사용하고 있습니다. 당신은 내가 다음에 와서 URL을 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

에서 또한 여기에 몇 가지 유용한 스크립트를 찾을 수 있습니다. 그것은 당신에게 보여주기 때문에 잘 작동합니다 :

  1. 현재 고아가 된 모든 사용자.
  2. 어떤 것이 수정되었는지.
  3. 고칠 수없는 것들.

다른 해결 방법을 사용하려면 수정하기 전에 고아 사용자 이름을 알아야합니다.

다음 코드는 다른 서버로 데이터베이스를 복원 한 후 호출되는 sproc에서 실행할 수 있습니다.

스크립트 :

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. 

결과 :

enter image description here

* 참고 : (위의 내 예제 스크린 샷) 고정되지 않은 4는 해당 사용자가 없었다 데이터베이스가 복원 된 대상 서버에서.

+3

야, 이거 놀랍다! 잘 했어. – CrazyTim

+2

이것은 이름에 작은 따옴표가있는 소수의 사용자 (그리고 그들이 고아가 된 일치하는 로그인)를 제외하고는 저에게 효과적이었습니다 (나는 그것들이 심지어 합법적이라고 놀랐습니다!). sp_change_users_login에 전달 된 매개 변수를 'username'대신 [username]을 전달하도록 변경 한 다음 해당 사용자도 작업했습니다. 그리고 '정상'사용자도 변경된 후에 올바르게 수정되었습니다. 감사합니다. 훌륭한 스크립트를 위해 @MikeTeeVee! –

+0

공격자가 엄청난 노력을 기울일 것이나 지킬 가치가 없을 것입니다. 그러나 어쨌든 경고로 : 드롭 테이블 사용자는 악의에 사용할 수있는 유효한 SQL 사용자 이름입니다. 편집 : 아마도 DBA는 이 문제를 해결했지만 사용자가 자신의 DB 사용자 이름을 만들 수있는 앱을 충분히 보았습니다. – Squid

관련 문제