Đăng nhập không đồng bộ hóa giữa các nhóm sẵn có


13

Chúng tôi có 2 máy chủ trong một nhóm Luôn luôn.

Mặc dù các tài khoản người dùng trong mỗi cơ sở dữ liệu được đồng bộ hóa tồn tại trên cả hai máy chủ, nhưng thông tin đăng nhập cấp cơ sở dữ liệu chỉ tồn tại trên một trong các máy chủ. Tức là DBINSTANCE-> Bảo mật-> Đăng nhập bị thiếu trên một máy chủ.

Do đó, khi có chuyển đổi dự phòng, tôi gặp lỗi đăng nhập trên máy chủ thứ hai (không có thông tin đăng nhập cấp thể hiện tương ứng).

Làm thế nào để tôi khắc phục vấn đề này? Tôi có nên thiết lập tài khoản người dùng theo cách đặc biệt không?


Tôi đã bắt đầu nhìn vào cái này thời gian gần đây cũng vậy, tôi cuộn của riêng tôi và hiện đang mô tả nó trong blog mới của tôi (Chủ yếu là vì lợi ích của riêng tôi khi tôi đi về phía trước và quên đi mọi thứ nhưng nếu nó giúp đỡ cho những người khác tất cả thì càng tốt) cuộc sống -and-dev.blogspot.co.uk/2015/04/ và điều này sẽ hiển thị Luôn theo dõi chuyển đổi dự phòng và đồng bộ hóa công việc / người dùng

Bạn có thể sử dụng plugin SSMS từ sqlskills Đồng bộ hóa đăng nhập và công việc của nhóm sẵn có
Kin Shah

Câu trả lời:


15

Tôi hiểu rằng nếu bạn không sử dụng Cơ sở dữ liệu có chứa , bạn sẽ phải đảm bảo đăng nhập được tạo theo cách thủ công.

Một cái gì đó giống như tập lệnh này từ SQLSoldier , ban đầu được đăng dưới dạng Chuyển thông tin đăng nhập sang Cơ sở dữ liệu , nên thực hiện thủ thuật.


Tôi mong muốn chuyển đổi một số cơ sở dữ liệu '05 sản xuất của chúng tôi sang định dạng chứa mới sau khi chúng tôi chuyển sang '12 trong một hoặc hai tuần tới. Trong lúc này, tôi đang sử dụng các công cụ của Idera để sao chép thông tin đăng nhập, công việc, v.v. sang ví dụ phụ.
Max Vernon

Đánh dấu là chính xác, bạn sẽ cần sử dụng cơ sở dữ liệu có chứa hoặc sao chép thủ công các thông tin đăng nhập vào tất cả các phiên bản trong cụm bằng cách sử dụng cùng một SID trên tất cả các phiên bản.
mrdenny

Hãy nhớ rằng tôi đang hỏi về Luôn luôn, không phản chiếu. Tôi đã thử tập lệnh, tuy nhiên bảng sys.servers chỉ chứa máy chủ cục bộ nên tôi gặp lỗi sau khi chạy quy trình được lưu trữ: Msg 7202, Level 11, State 2, Line 1 Could not find server 'otherserver' in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.
John

Tôi đã tìm ra nó và đăng một câu trả lời mới phù hợp cho Luôn luôn.
Giăng

@JohnHughes Kịch bản này phù hợp với Luôn luôn. Tuy nhiên, như bạn đã chỉ ra bởi thông báo lỗi, cần phải tạo một máy chủ được liên kết giữa các phiên bản.
Mark Storey-Smith

6

Bạn phải sử dụng Cơ sở dữ liệu có chứa hoặc bạn phải tạo lại người dùng trên (các) máy chủ khác có cùng mật khẩu băm và SID.

Tập lệnh để thực hiện việc này được cung cấp bởi Microsoft: Cách chuyển thông tin đăng nhập và mật khẩu giữa các phiên bản của SQL Server

Giải pháp của Mark đã đúng một phần tuy nhiên giải pháp được đề xuất của anh là dành cho cơ sở dữ liệu Mirrored, trái ngược với Luôn luôn, đó là những gì các câu hỏi yêu cầu.


2
Giải pháp cho cơ sở dữ liệu được nhân đôi khác với giải pháp cho Nhóm khả dụng như thế nào (lưu ý: Luôn luôn là nhãn tiếp thị cho một loạt các công nghệ, không phải là một tính năng)? Tiêu đề của một bài đăng trên blog không thay đổi thực tế rằng nó đang khôi phục các thông tin đăng nhập bị thiếu - trong đó, bản thân nó, không liên quan gì đến việc bạn có đang sử dụng phản chiếu, nhóm khả dụng, vận chuyển nhật ký, sao lưu / khôi phục thủ công, v.v.
Aaron Bertrand

Thật không may, tôi không thể luôn luôn sử dụng tài khoản AD. Chúng tôi đang vật lộn với một cách để so sánh các mật khẩu. Có phải chúng ta không đúng khi cho rằng nếu mật khẩu không khớp, việc chuyển đổi dự phòng giữa các máy chủ bản sao sẽ thất bại?

1

Tôi đang trả lời bài viết sau một thời gian dài nhưng nó có thể giúp đỡ người khác với vấn đề tương tự. PowerShell có thể được sử dụng để sao chép thông tin đăng nhập từ bản sao chính sang bản sao phụ. Chi tiết có thể được tìm thấy ở đây https://maq.guru/synyncizing-sql-server-logins-in-an-always-on-avcellence-group/ .

Tiết lộ đầy đủ: Tôi sở hữu các trang web trên.

Tập lệnh PowerShell:

$Conn=New-Object System.Data.SqlClient.SQLConnection
$QueryTimeout = 120
$ConnectionTimeout = 30

###########################################################
# Execute Query function 
###########################################################
Function executequery($Query, $QueryTimeout, $ServerName)
{
    $Datatable = New-Object System.Data.DataTable
    $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$Database,$ConnectionTimeout
    $Conn.ConnectionString=$ConnectionString
    $Cmd=New-Object system.Data.SqlClient.SqlCommand($Query,$Conn)
    $Cmd.CommandTimeout=$QueryTimeout

            do
                {   
                    $Conn.Open()
                    Start-Sleep -Seconds 2
                }while ($Conn.State -ne 'Open')

            $Reader = $cmd.ExecuteReader()
            $Datatable.Load($Reader)
            $Conn.Close()
            return $Datatable    
}


###########################################################
# Create spHexaDecimal Stored Procedure
###########################################################

Function CreatespHexaDecimal ($ServerName)
    {
    $Query='USE [master];
                GO
                SET ANSI_NULLS ON;
                GO
                SET QUOTED_IDENTIFIER ON;
                GO
                CREATE PROCEDURE [dbo].[spHexaDecimal]
                (
                    @BinValue VARBINARY(256)
                    , @HexValue VARCHAR(514) OUTPUT
                )
                AS

                DECLARE @CharValue VARCHAR(514)
                DECLARE @i INT
                DECLARE @Length INT
                DECLARE @HexString CHAR(16)

                SET @CharValue = ''0x''
                SET @i = 1
                SET @Length = DATALENGTH(@BinValue)
                SET @HexString = ''0123456789ABCDEF''

                WHILE (@i <= @Length)
                BEGIN

                    DECLARE @TempInt INT
                    DECLARE @FirstInt INT
                    DECLARE @SecondInt INT

                    SET @TempInt = CONVERT(INT, SUBSTRING(@BinValue, @i, 1))
                    SET @FirstInt = FLOOR(@TempInt/16)
                    SET @SecondInt = @TempInt - (@FirstInt * 16)
                    SET @CharValue = @CharValue 
                                        + SUBSTRING(@HexString, @FirstInt + 1, 1)
                                        + SUBSTRING(@HexString, @SecondInt + 1, 1)

                    SET @i = @i + 1

                END --WHILE (@i <= @Length)

                SET @HexValue = @CharValue'

                Invoke-Sqlcmd -Query $Query -ServerInstance $ServerName
    }


###########################################################
# CheckStroedProc 
###########################################################

Function CheckStoredProc ($Server)
{
    $Query= 'SELECT 1 AS ExistCheck
             FROM   sysobjects 
             WHERE  id = object_id(N''[dbo].[spHexaDecimal]'') 
                 AND OBJECTPROPERTY(id, N''IsProcedure'') = 1 '

    $Result=executequery $Query $QueryTimeout $Server
    $Exist=$Result | SELECT -ExpandProperty ExistCheck
    IF ($Exist -ne 1)
        {
            CreatespHexaDecimal -ServerName $Server
        }
}

###########################################################
# Get Login Script
###########################################################

Function Get-Script ($Server)
{

$Query='DECLARE @TempTable TABLE
(Script NVARCHAR(MAX))
DECLARE @Login NVARCHAR (MAX)
DECLARE CURLOGIN CURSOR FOR
SELECT name 
FROM sys.server_principals
WHERE CONVERT(VARCHAR(24),create_date,103) = CONVERT(VARCHAR(24),GETDATE(),103)
    OR CONVERT(VARCHAR(24),modify_date,103) = CONVERT(VARCHAR(24),GETDATE(),103)

OPEN CURLOGIN
    FETCH NEXT FROM CURLOGIN INTO @Login

WHILE @@FETCH_STATUS = 0
BEGIN
    SET NOCOUNT ON
    DECLARE @Script NVARCHAR (MAX)
    DECLARE @LoginName VARCHAR(500)= @Login
    DECLARE @LoginSID VARBINARY(85)
    DECLARE @SID_String VARCHAR(514)
    DECLARE @LoginPWD VARBINARY(256)
    DECLARE @PWD_String VARCHAR(514)
    DECLARE @LoginType CHAR(1)
    DECLARE @is_disabled BIT
    DECLARE @default_database_name SYSNAME
    DECLARE @default_language_name SYSNAME
    DECLARE @is_policy_checked BIT
    DECLARE @is_expiration_checked BIT
    DECLARE @createdDateTime DATETIME



    SELECT @LoginSID = P.[sid]
        , @LoginType = P.[type]
        , @is_disabled = P.is_disabled 
        , @default_database_name = P.default_database_name 
        , @default_language_name = P.default_language_name 
        , @createdDateTime = P.create_date 
    FROM sys.server_principals P
    WHERE P.name = @LoginName

    /** Some Output **/
    SET @Script = ''''




    --If the login is a SQL Login, then do a lot of stuff...
    IF @LoginType = ''S''
    BEGIN

        SET @LoginPWD = CAST(LOGINPROPERTY(@LoginName, ''PasswordHash'') AS VARBINARY(256))

        EXEC spHexaDecimal @LoginPWD, @PWD_String OUT   
        EXEC spHexaDecimal @LoginSID, @SID_String OUT

        SELECT @is_policy_checked = S.is_policy_checked
            , @is_expiration_checked = S.is_expiration_checked
        FROM sys.sql_logins S

        /** Create Script **/
        SET @Script = @Script + CHAR(13) + CHAR(13)
                        + ''IF EXISTS (SELECT name FROM sys.server_principals WHERE name= ''''''+ @LoginName + '''''') '' 
                        + CHAR(13) + '' BEGIN ''
                        + CHAR(13) + CHAR(9) + '' ALTER LOGIN '' + QUOTENAME(@LoginName)
                        + CHAR(13) + CHAR(9) + ''WITH PASSWORD = '' + @PWD_String + '' HASHED''
                        + CHAR(13) + CHAR(9) + '', DEFAULT_DATABASE = ['' + @default_database_name + '']''
                        + CHAR(13) + CHAR(9) + '', DEFAULT_LANGUAGE = ['' + @default_language_name + '']''
                        + CHAR(13) + CHAR(9) + '', CHECK_POLICY '' + CASE WHEN @is_policy_checked = 0 THEN ''=OFF'' ELSE ''=ON'' END
                        + CHAR(13) + CHAR(9) + '', CHECK_EXPIRATION '' + CASE WHEN @is_expiration_checked = 0 THEN ''=OFF'' ELSE ''=ON'' END
                        + CHAR(13) + '' END ''
                        + CHAR(13) + ''ELSE''
                        + CHAR(13) + '' BEGIN ''
                        + CHAR(13) + CHAR(9) + '' CREATE LOGIN '' + QUOTENAME(@LoginName)
                        + CHAR(13) + CHAR(9) + ''WITH PASSWORD = '' + @PWD_String + '' HASHED''
                        + CHAR(13) + CHAR(9) + '', SID = '' + @SID_String
                        + CHAR(13) + CHAR(9) + '', DEFAULT_DATABASE = ['' + @default_database_name + '']''
                        + CHAR(13) + CHAR(9) + '', DEFAULT_LANGUAGE = ['' + @default_language_name + '']''
                        + CHAR(13) + CHAR(9) + '', CHECK_POLICY '' + CASE WHEN @is_policy_checked = 0 THEN ''=OFF'' ELSE ''=ON'' END
                        + CHAR(13) + CHAR(9) + '', CHECK_EXPIRATION '' + CASE WHEN @is_expiration_checked = 0 THEN ''=OFF'' ELSE ''=ON'' END
                        + CHAR(13) + '' END ''

        SET @Script = @Script + CHAR(13) + CHAR(13)
                        + '' ALTER LOGIN ['' + @LoginName + '']''
                        + CHAR(13) + CHAR(9) + ''WITH DEFAULT_DATABASE = ['' + @default_database_name + '']''
                        + CHAR(13) + CHAR(9) + '', DEFAULT_LANGUAGE = ['' + @default_language_name + '']''

    END
    ELSE
    BEGIN

        --The login is a NT login (or group).
        SET @Script = @Script + CHAR(13) + CHAR(13)
                        + ''IF NOT EXISTS (SELECT name FROM sys.server_principals WHERE name= ''''''+ @LoginName + '''''') '' 
                        + CHAR(13) + '' BEGIN ''
                        + CHAR(13) + CHAR(9) + '' CREATE LOGIN '' + QUOTENAME(@LoginName) + '' FROM WINDOWS''
                        + CHAR(13) + CHAR(9) + ''WITH DEFAULT_DATABASE = ['' + @default_database_name + '']''
                        + CHAR(13) + '' END ''
    END

    /******************************************************************************************/
    --This section deals with the Server Roles that belong to that login...
    /******************************************************************************************/

    DECLARE @ServerRoles TABLE
        (
        ServerRole SYSNAME
        , MemberName SYSNAME
        , MemberSID VARBINARY(85)
        )

    INSERT INTO @ServerRoles EXEC sp_helpsrvrolemember

    --Remove all Roles
    SET @Script = @Script + CHAR(13)
    SET @Script = @Script 
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''sysadmin''''''
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''securityadmin''''''
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''serveradmin'''''' 
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''setupadmin'''''' 
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''processadmin''''''
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''diskadmin'''''' 
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''dbcreator'''''' 
                            + CHAR(13) + ''EXEC sp_dropsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + ''''''bulkadmin'''''' 

    /** Output to script... **/
    --SET @Script = @Script + CHAR(13) + CHAR(13)

    --Test if there are any server roles for this login...
    IF EXISTS(SELECT 1 FROM @ServerRoles WHERE MemberName = @LoginName)
    BEGIN

        SET @Script = @Script + CHAR(13)

        DECLARE @ServerRole SYSNAME
        DECLARE curRoles CURSOR LOCAL STATIC FORWARD_ONLY

        FOR SELECT ServerRole 
            FROM @ServerRoles
            WHERE MemberName = @LoginName

        OPEN curRoles

        FETCH NEXT FROM curRoles
        INTO @ServerRole

        WHILE @@FETCH_STATUS = 0
        BEGIN

            /** Output to Script **/
            SET @Script = @Script 
                            + CHAR(13) + ''EXEC sp_addsrvrolemember '' + QUOTENAME(@LoginName, '''''''') + '', '' + QUOTENAME(@ServerRole, '''''''')

            FETCH NEXT FROM curRoles
            INTO @ServerRole

        END

        --Cleanup.
        CLOSE curRoles
        DEALLOCATE curRoles

    END
    INSERT INTO @TempTable
    VALUES(@Script)

    FETCH NEXT FROM CURLOGIN INTO @Login
END
CLOSE CURLOGIN;
DEALLOCATE CURLOGIN;
SELECT Script FROM @TempTable'

$Result=executequery $Query $QueryTimeout $Server

If($Result -eq $null)
    {
        break
    }
Else
    {
        [Void][System.IO.Directory]::CreateDirectory("C:\temp")
        $Path = "C:\temp"
        $Acl = (Get-Item $Path).GetAccessControl('Access')
        $Username = Get-WmiObject win32_service | Where name -EQ 'SQLSERVERAGENT' | Select -ExpandProperty StartName
        $Ar = New-Object System.Security.AccessControl.FileSystemAccessRule($Username, 'Full', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
        $Acl.SetAccessRule($Ar)
        Set-Acl -path $Path -AclObject $Acl
        $Result | select -ExpandProperty Script | Out-File C:\temp\Script.txt
    }
}


###########################################################
# SCRIPT BODY 
###########################################################

$Query= "SELECT ISNULL(SERVERPROPERTY ('InstanceName'), 'DEFAULT') InstanceName 
            , name AGName
            , replica_server_name Replica
            , role_desc 
            FROM sys.dm_hadr_availability_replica_states hars 
            INNER JOIN sys.availability_groups ag ON ag.group_id = hars.group_id 
            INNER JOIN sys.availability_replicas ar ON ar.replica_id = hars.replica_id
            WHERE role_desc = 'PRIMARY'
            ORDER BY role_desc asc"
Write-Host "Is this Primary Replica?"
$Result=executequery $Query $QueryTimeout $PrimaryReplica
If ($Result -eq $null)
    {
        Write-Host "No, it's not."
        break
    }
Else
    {
        Write-Host "Yes, it is."
        $PrimaryReplica= $Result | select -ExpandProperty Replica
        Write-Host "Check for prerequisite, if not present deploy it."
        CheckStoredProc -Server $PrimaryReplica
        Write-Host "Get script for new/modifies login(s)."
        Get-Script -Server $PrimaryReplica

        $Query= "SELECT ISNULL(SERVERPROPERTY ('InstanceName'), 'DEFAULT') InstanceName 
                    , name AGName
                    , replica_server_name Replica
                    , role_desc 
                    FROM sys.dm_hadr_availability_replica_states hars 
                    INNER JOIN sys.availability_groups ag ON ag.group_id = hars.group_id 
                    INNER JOIN sys.availability_replicas ar ON ar.replica_id = hars.replica_id
                    WHERE role_desc = 'SECONDARY'
                    ORDER BY role_desc asc"

        $Result=executequery $Query $QueryTimeout $PrimaryReplica
        $SecondaryReplicas= $Result | select -ExpandProperty Replica
        $Query= Get-Content -Path 'C:\temp\Script.txt' | Out-String
        ForEach($SecondaryReplica in $SecondaryReplicas)
            {
                Invoke-Sqlcmd -Query $Query -ServerInstance $SecondaryReplica
                Write-Host "Successfully copied login(s) to $SecondaryReplica"
            }
        Remove-Item C:\temp\Script.txt
    }

2
Cảm ơn Muhammad, bạn có thể đưa vào một số nội dung của liên kết không? Nếu liên kết chết, câu hỏi của bạn sẽ trở nên ít hữu ích hơn nhiều!
LowlyDBA

@LowlyDBA, tôi đã cố gắng đặt tập lệnh ở đây nhưng tiếc là nó quá dài :( Liên kết sẽ không chết khi tôi sở hữu trang web này.
Muhammad

Kịch bản không dài lắm. Tôi sẽ thêm nó cho bạn. Và trong trường hợp đó, bạn cần tiết lộ liên kết của mình khi đăng liên kết của riêng bạn.
LowlyDBA

Xin lỗi @LowlyDBA, tôi không biết về việc tiết lộ. Tôi đã cố gắng đặt kịch bản ở đây trong phần bình luận nhưng nó bị giới hạn ở một số ký tự nhất định. Tôi đã thêm kịch bản hoàn chỉnh. Cảm ơn
Muhammad

Thật đáng xấu hổ khi đồng bộ hóa cấp máy chủ không phải là một phần của AG. Câu trả lời của bạn nhận được một upvote cho bài viết gọi MS trên đó.
youcantryreachingme

0

Bạn phải sử dụng thông tin đăng nhập Miền Windows và tạo chúng trong mọi trường hợp, vì SID được quản lý theo thư mục hoạt động, bạn sẽ có thể truy cập vào tất cả các thành viên bản sao của nhóm khả dụng nếu đăng nhập tồn tại trong bản sao chính. tùy chọn khác bạn phải sử dụng một chứng chỉ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.