暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

AlwaysOn环境下孤立账号处理

问题:

在AlwaysOn环境下,如果分别手动在主节点和辅助节点建立登录帐号(实例级别),在每次AlwaysOn进行切换时,由于SID不一样,会出现权限不一致问题,导致孤立账号访问不了指定数据库。

原因:

每台服务器上的SQLServer登录的SID(安全标识符)不匹配。尽管对于登录的名字是相同的,但登录经由该login的SID解决。

处理方法:

先在主节点建立SQLServer账号,然后使用导出登录账号脚本的方式,同步到辅助节点。这样两个节点的SID就完全一致,不用再处理孤立账号。
当然还有一种情况是全部使用域帐号登录,也不存在孤立账号的问题。

导出login的脚本

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

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 @Principal_id int
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
DECLARE @language sysname
DECLARE @rolename sysname
DECLARE login_curs CURSOR FOR SELECT 
    p.principal_id,
    p.sid, 
    p.name, 
    p.type, 
    p.is_disabled, 
    p.default_database_name, 
    p.default_language_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'

OPEN login_curs

FETCH NEXT FROM login_curs INTO @Principal_id, @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @language, @hasaccess, @denylogin
IF (@@fetch_status = -1)
BEGIN
  PRINT 'No login(s) found.'
  CLOSE login_curs
  DEALLOCATE login_curs
  RETURN
END
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 + '], DEFAULT_LANGUAGE = [' + @language + ']'
        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 + '], DEFAULT_LANGUAGE = [' + @language + ']'

            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
        PRINT 'GO'
        DECLARE server_role_members_curs CURSOR FOR 
            SELECT 
                (SELECT [name] FROM sys.server_principals WHERE principal_id = role_principal_id) AS rolename
            FROM 
                sys.server_role_members 
            WHERE 
                member_principal_id = @Principal_id
        OPEN server_role_members_curs

        FETCH NEXT FROM server_role_members_curs INTO @rolename
        WHILE (@@fetch_status <> -1)
        BEGIN
            SELECT @tmpstr = 'EXEC master..sp_addsrvrolemember @loginame = N''' + @name + ''', @rolename = N''' + @rolename + ''''
            PRINT @tmpstr
            PRINT 'GO'
            FETCH NEXT FROM server_role_members_curs INTO @rolename
        END
        CLOSE server_role_members_curs
        DEALLOCATE server_role_members_curs        
    END
    FETCH NEXT FROM login_curs INTO @Principal_id, @SID_varbinary, @name, @type, @is_disabled, @defaultdb, @language, @hasaccess, @denylogin
END
CLOSE login_curs
DEALLOCATE login_curs
GO

DROP PROCEDURE #sp_hexadecimal
GO
最后修改时间:2024-10-21 14:01:18
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论