데이터베이스를 이동 한 후 (백업, 복원) 사용자를 다시 추가해야합니다


46

SQL Server Management Studio에서 데이터베이스 백업 및 복원을 사용하여 데이터베이스 (SQL Express 2012)를 개발 시스템에서 서버로 또는 그 반대로 이동하는 경우가 있습니다.

이 작업을 수행 할 때마다 대상 컴퓨터의 응용 프로그램은 데이터베이스 사용자 (데이터베이스, 보안, SQL Server Management Studio의 사용자)에서 사용하는 "george"사용자를 삭제하고 다음과 같이 다시 추가 할 때까지 데이터베이스에 액세스 할 수 없습니다. 보안, 로그인, george / properties, 사용자 맵핑에서 소유자.

더 좋은 방법이 있습니까? 조금 복잡해 보입니다.


4
로그인의 SID가 서버간에 일치하지 않습니다. CREATE LOGIN명령문 에서 SID를 수동으로 지정하십시오 .
Jon Seigel

답변:


59

이것은 로그인사용자 의 차이점 과 이들이 서로 관련되는 방식입니다.

  • 로그인-엔터티가 SQL Server 인스턴스에 연결할 수 있도록하는 인스턴스 수준 보안 주체 특성상 인스턴스의 데이터베이스에 대한 액세스 권한을 부여하지 않습니다. 이에 대한 예외는 sysadmin 권한이있는 로그인은 sysadmin이기 때문에 데이터베이스를 사용할 수 있지만 sysadmin 레벨 권한으로 인해 데이터베이스를 사용할 수 있다는 것입니다.
  • 사용자-엔터티가 SQL Server 데이터베이스에 연결할 수 있도록하는 데이터베이스 수준 보안 주체 사용자는 SID를 통한 로그인과 관련되어 있으며, 둘 사이의 관계를 생성하고 로그인을 인스턴스에 연결 한 다음 관련 사용자를 사용하여 데이터베이스에 연결합니다.

복원시 SQL 인증 로그인 및 데이터베이스 사용자에게 일반적으로 발생하는 것은 SIDS가 동기화되지 않아 관계가 손상된다는 것입니다. SQL Server의 눈에는 이러한 주체가 더 이상 연결되어 있지 않으므로 해당 로그인을 사용하여 데이터베이스에 연결하기 전에이 관계를 복구해야합니다. 다음 SQL을 사용하여이 문제를 해결할 수 있습니다.

ALTER USER [foo] WITH LOGIN=[foo]

데이터베이스 컨텍스트에서 다음 쿼리를 사용하여 고아를 확인할 수 있습니다.

select
    dp.name [user_name]
    ,dp.type_desc [user_type]
    ,isnull(sp.name,'Orhphaned!') [login_name]
    ,sp.type_desc [login_type]
from   
    sys.database_principals dp
    left join sys.server_principals sp on (dp.sid = sp.sid)
where
    dp.type in ('S','U','G')
    and dp.principal_id >4
order by sp.name

"Windows NT 사용자 또는 그룹 'ca-v2-staging'을 찾을 수 없습니다. 이름을 다시 확인하십시오."오류가 발생합니다. 첫 번째 쿼리를 실행하면 초 쿼리가 제대로 작동하고 손실 된 SQL 사용자 "ca-v2-staging"을 반환합니다.
토마스

3

데이터베이스를 포함 된 데이터베이스 로 변경하는 것을 볼 수 있습니다 . 포함 된 데이터베이스 사용자는 로그인을 통해 인스턴스 레벨이 아닌 데이터베이스에 의해 인증됩니다. 데이터베이스를 다른 인스턴스로보다 간단하게 이동할 수 있습니다.

그렇지 않은 경우이 Microsoft 지원 KB에 제공된 sp_help_revlogin 스크립트를 사용하여 로그인 정보를 백업 할 수 있습니다. 그리고 새 인스턴스에서 출력 스크립트를 실행하십시오.


3

아래 스크립트를 사용하여 사용자 계정 및 로그인을 마이그레이션 / 생성합니다. 데이터베이스를 복원 한 서버에서이를 실행하고 원래 서버 이름을 프로 시저에 매개 변수로 제공하십시오.

다른 곳에서 얻은 절차에 대해서는 아무런 신용도 얻지 못하지만 정상적으로 작동합니다.

USE [master]
GO
/****** Object:  StoredProcedure [dbo].[stp_Admin_ReplicateUserLogins]    Script Date: 10/29/2015 08:22:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


ALTER Procedure [dbo].[stp_Admin_ReplicateUserLogins] --'OriginalSourceDatabase', 1
    @PartnerServer sysname,
    @Debug bit = 0 -- 0 = Create Users, 1 = Display SQL command but doesn't execute query.
As

Declare @MaxID int,
    @CurrID int,
    @SQL nvarchar(max),
    @LoginName sysname,
    @IsDisabled int,
    @Type char(1),
    @SID varbinary(85),
    @SIDString nvarchar(100),
    @PasswordHash varbinary(256),
    @PasswordHashString nvarchar(300),
    @RoleName sysname,
    @Machine sysname,
    @PermState nvarchar(60),
    @PermName sysname,
    @Class tinyint,
    @MajorID int,
    @ErrNumber int,
    @ErrSeverity int,
    @ErrState int,
    @ErrProcedure sysname,
    @ErrLine int,
    @ErrMsg nvarchar(2048)
Declare @Logins Table (LoginID int identity(1, 1) not null primary key,
                        [Name] sysname not null,
                        [SID] varbinary(85) not null,
                        IsDisabled int not null,
                        [Type] char(1) not null,
                        PasswordHash varbinary(256) null)
Declare @Roles Table (RoleID int identity(1, 1) not null primary key,
                    RoleName sysname not null,
                    LoginName sysname not null)
Declare @Perms Table (PermID int identity(1, 1) not null primary key,
                    LoginName sysname not null,
                    PermState nvarchar(60) not null,
                    PermName sysname not null,
                    Class tinyint not null,
                    ClassDesc nvarchar(60) not null,
                    MajorID int not null,
                    SubLoginName sysname null,
                    SubEndPointName sysname null)

Set NoCount On;

If CharIndex('\', @PartnerServer) > 0
  Begin
    Set @Machine = LEFT(@PartnerServer, CharIndex('\', @PartnerServer) - 1);
  End
Else
  Begin
    Set @Machine = @PartnerServer;
  End

-- Get all Windows logins from principal server
Set @SQL = 'Select P.name, P.sid, P.is_disabled, P.type, L.password_hash' + CHAR(10) +
        'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals P' + CHAR(10) +
        'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.sql_logins L On L.principal_id = P.principal_id' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'and P.Name Not like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;';

Insert Into @Logins (Name, SID, IsDisabled, Type, PasswordHash)
Exec sp_executesql @SQL;

-- Get all roles from principal server
Set @SQL = 'Select RoleP.name, LoginP.name' + CHAR(10) +
        'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_role_members RM' + CHAR(10) +
        'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals RoleP' +
        CHAR(10) + char(9) + 'On RoleP.principal_id = RM.role_principal_id' + CHAR(10) +
        'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals LoginP' +
        CHAR(10) + char(9) + 'On LoginP.principal_id = RM.member_principal_id' + CHAR(10) +
        'Where LoginP.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And LoginP.name <> ''sa''' + CHAR(10) +
        'And LoginP.name Not Like ''##%''' + CHAR(10) +
        'And LoginP.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And RoleP.type = ''R''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', LoginP.name) = 0;';

Insert Into @Roles (RoleName, LoginName)
Exec sp_executesql @SQL;

-- Get all explicitly granted permissions
Set @SQL = 'Select P.name Collate database_default,' + CHAR(10) +
        '   SP.state_desc, SP.permission_name, SP.class, SP.class_desc, SP.major_id,' + CHAR(10) +
        '   SubP.name Collate database_default,' + CHAR(10) +
        '   SubEP.name Collate database_default' + CHAR(10) +
        'From ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals P' + CHAR(10) +
        'Inner Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_permissions SP' + CHAR(10) +
        CHAR(9) + 'On SP.grantee_principal_id = P.principal_id' + CHAR(10) +
        'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.server_principals SubP' + CHAR(10) +
        CHAR(9) + 'On SubP.principal_id = SP.major_id And SP.class = 101' + CHAR(10) +
        'Left Join ' + QUOTENAME(@PartnerServer) + '.master.sys.endpoints SubEP' + CHAR(10) +
        CHAR(9) + 'On SubEP.endpoint_id = SP.major_id And SP.class = 105' + CHAR(10) +
        'Where P.type In (''U'', ''G'', ''S'')' + CHAR(10) +
        'And P.name <> ''sa''' + CHAR(10) +
        'And P.name Not Like ''##%''' + CHAR(10) +
        'And P.name Not Like ''NT SERVICE%''' + CHAR(10) +
        'And CharIndex(''' + @Machine + '\'', P.name) = 0;'

Insert Into @Perms (LoginName, PermState, PermName, Class, ClassDesc, MajorID, SubLoginName, SubEndPointName)
Exec sp_executesql @SQL;



Select @MaxID = Max(LoginID), @CurrID = 1
From @Logins;

While @CurrID <= @MaxID
  Begin
    Select @LoginName = Name,
        @IsDisabled = IsDisabled,
        @Type = [Type],
        @SID = [SID],
        @PasswordHash = PasswordHash
    From @Logins
    Where LoginID = @CurrID;

    If Not Exists (Select 1 From sys.server_principals
                Where name = @LoginName)
      Begin
        Set @SQL = 'Create Login ' + quotename(@LoginName)
        If @Type In ('U', 'G')
          Begin
            Set @SQL = @SQL + ' From Windows;'
          End
        Else
          Begin
            Set @PasswordHashString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@PasswordHash"))', 'nvarchar(300)');

            Set @SQL = @SQL + ' With Password = ' + @PasswordHashString + ' HASHED, ';

            Set @SIDString = '0x' +
                Cast('' As XML).value('xs:hexBinary(sql:variable("@SID"))', 'nvarchar(100)');
            Set @SQL = @SQL + 'SID = ' + @SIDString + ';';
          End

        If @Debug = 0
          Begin
            Begin Try
                Exec sp_executesql @SQL;
            End Try
            Begin Catch
                Set @ErrNumber = ERROR_NUMBER();
                Set @ErrSeverity = ERROR_SEVERITY();
                Set @ErrState = ERROR_STATE();
                Set @ErrProcedure = ERROR_PROCEDURE();
                Set @ErrLine = ERROR_LINE();
                Set @ErrMsg = ERROR_MESSAGE();
                RaisError(@ErrMsg, 1, 1);
            End Catch
          End
        Else
          Begin
            Print @SQL;
          End

        If @IsDisabled = 1
          Begin
            Set @SQL = 'Alter Login ' + quotename(@LoginName) + ' Disable;'
            If @Debug = 0
              Begin
                Begin Try
                    Exec sp_executesql @SQL;
                End Try
                Begin Catch
                    Set @ErrNumber = ERROR_NUMBER();
                    Set @ErrSeverity = ERROR_SEVERITY();
                    Set @ErrState = ERROR_STATE();
                    Set @ErrProcedure = ERROR_PROCEDURE();
                    Set @ErrLine = ERROR_LINE();
                    Set @ErrMsg = ERROR_MESSAGE();
                    RaisError(@ErrMsg, 1, 1);
                End Catch
              End
            Else
              Begin
                Print @SQL;
              End
          End
        End
    Set @CurrID = @CurrID + 1;
  End

Select @MaxID = Max(RoleID), @CurrID = 1
From @Roles;

While @CurrID <= @MaxID
  Begin
    Select @LoginName = LoginName,
        @RoleName = RoleName
    From @Roles
    Where RoleID = @CurrID;

    If Not Exists (Select 1 From sys.server_role_members RM
                Inner Join sys.server_principals RoleP
                    On RoleP.principal_id = RM.role_principal_id
                Inner Join sys.server_principals LoginP
                    On LoginP.principal_id = RM.member_principal_id
                Where LoginP.type In ('U', 'G', 'S')
                And RoleP.type = 'R'
                And RoleP.name = @RoleName
                And LoginP.name = @LoginName)
      Begin
        If @Debug = 0
          Begin
            Exec sp_addsrvrolemember @rolename = @RoleName,
                            @loginame = @LoginName;
          End
        Else
          Begin
            Print 'Exec sp_addsrvrolemember @rolename = ''' + @RoleName + ''',';
            Print '     @loginame = ''' + @LoginName + ''';';
          End
      End

    Set @CurrID = @CurrID + 1;
  End

Select @MaxID = Max(PermID), @CurrID = 1
From @Perms;

While @CurrID <= @MaxID
  Begin
    Select @PermState = PermState,
        @PermName = PermName,
        @Class = Class,
        @LoginName = LoginName,
        @MajorID = MajorID,
        @SQL = PermState + space(1) + PermName + SPACE(1) +
            Case Class When 101 Then 'On Login::' + QUOTENAME(SubLoginName)
                    When 105 Then 'On ' + ClassDesc + '::' + QUOTENAME(SubEndPointName)
                    Else '' End +
            ' To ' + QUOTENAME(LoginName) + ';'
    From @Perms
    Where PermID = @CurrID;

    If Not Exists (Select 1 From sys.server_principals P
                Inner Join sys.server_permissions SP On SP.grantee_principal_id = P.principal_id
                Where SP.state_desc = @PermState
                And SP.permission_name = @PermName
                And SP.class = @Class
                And P.name = @LoginName
                And SP.major_id = @MajorID)
      Begin
        If @Debug = 0
          Begin
            Begin Try
                Exec sp_executesql @SQL;
            End Try
            Begin Catch
                Set @ErrNumber = ERROR_NUMBER();
                Set @ErrSeverity = ERROR_SEVERITY();
                Set @ErrState = ERROR_STATE();
                Set @ErrProcedure = ERROR_PROCEDURE();
                Set @ErrLine = ERROR_LINE();
                Set @ErrMsg = ERROR_MESSAGE();
                RaisError(@ErrMsg, 1, 1);
            End Catch
          End
        Else
          Begin
            Print @SQL;
          End
      End

    Set @CurrID = @CurrID + 1;
  End


Set NoCount Off;

"데이터베이스를 복원 한 서버에서 서버를 실행하고 원래 서버 이름을 프로 시저에 매개 변수로 제공하십시오." 감사합니다. 어떻게 "원본 서버 이름을 프로 시저에 매개 변수로 제공"합니까?

3

여기에 나를 위해 일한 솔루션입니다. 그것이하는 일은 :

  1. 고아 사용자 목록 : EXEC sp_change_users_login 'REPORT'
  2. 사용자를 수정하십시오. EXEC sp_change_users_login 'UPDATE_ONE','<userName>','<userName>'

1

데이터베이스의 모든 사용자를 데이터베이스 서버의 비슷한 이름의 로그인에 항상 다시 연결하려고 할 수 있습니다.

ALTER 
    AUTHORIZATION
    ON 
        SCHEMA::db_owner
    TO 
        dbo
GO

DECLARE @username VARCHAR(64)
DECLARE @sql nvarchar(max)

DECLARE 
    UserCursor 
CURSOR FOR 
    SELECT 
        [name]
    FROM 
        sysusers
    WHERE 
        [name] NOT IN('dbo','guest','INFORMATION_SCHEMA','sys','public')
        AND 
        LEFT([name],3) <> 'db_' 
        AND 
        [name] NOT LIKE '%]%'

OPEN 
    UserCursor
FETCH NEXT 
FROM 
    UserCursor 
    INTO 
        @username
WHILE @@fetch_status <> -1
BEGIN
    SET @sql = 'ALTER USER [' + @username + '] WITH LOGIN=[' + @username + ']'
    PRINT @sql
    EXEC dbo.sp_executesql @sql;
    FETCH NEXT 
    FROM 
        UserCursor
        INTO 
            @username
END
CLOSE UserCursor
DEALLOCATE UserCursor

0

나는 포스터 문제에 대한이 간단한 수정에 주목할 가치가 있다고 생각했다. 사용자 이름이 보안> 데이터베이스의 사용자에 있지만 'login name'사용자의 속성에서 누락 된 경우 한 서버에서 다른 서버의 개발 / 테스트 데이터베이스로 프로덕션 데이터베이스를 복원 할 때 SQL Server 2008에서 실행되는 스크립트 입니다. 일반 탭 :

EXEC sp_change_users_login 'Auto_Fix','missingloginnamehere', NULL, 'passwordgoeshere';

MSDN 참조 here 이 기사에서는 최신 버전의 SQL 대신 ALTER USER를 사용하는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.