orphan user是某个数据库的user,只有user name而没有login,即,在存在于sys.database_principals 中, 而不存在于 sys.server_principals 中。一般情况下,将备份的数据库在其它Server上还原时,会产生orphan user。
一,查看Orphaned Users
Login 和 User的Mapping 关系是通过SID(security ID)来关联的,如果一个SID 存在于sys.database_principals,而不存在于 sys.server_principals,那么这个User 除非是system user,否则就是orphaned user.
1,使用以下脚本查看Orphaned Users
select dp.name as UserName,dp.type,dp.type_desc,dp.default_schema_name,dp.is_fixed_role, dp.authentication_type,dp.authentication_type_desc,dp.sid,dp.principal_id from sys.database_principals dp left join sys.server_principals sp on dp.sid=sp.sid where sp.sid is null and dp.[type] IN (N'U', N'S',N'G') AND dp.is_fixed_role = 0 AND dp.[Name] NOT IN (N'dbo', N'guest', N'sys', N'INFORMATION_SCHEMA')
sys.database_principals Principal type:
sys.server_principals Principal type:
2,创建SQL Login, Windows Login 和 Windows Group
既然是User没有对应的Login,那么就需要创建Login,在创建Login时,需要指定login name,SQL Login Name 和Windows Login Name 的格式不相同的。
2.1,创建Windows Login和 Windows Group的语法相同
When you are creating logins that are mapped from a Windows domain account, you must use the pre-Windows 2000 user logon name in the format [<domainName>\<login_name>].
CREATE LOGIN [DomainName\WindowsLoginName] -- or [DomainName\WindowsGroupName] FROM WINDOWS WITH DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english]
2.2,创建SQL Login
SQL Server authentication logins are type sysname and must conform to the rules for Identifiers and cannot contain a '\'. Windows logins can contain a '\'.
CREATE LOGIN [SQLLoginName] WITH PASSWORD=N'faLwQqnC8vD+eP+Ft13/pAXrJ2b7LlBM9BNEwnzIYDo=', DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english], CHECK_EXPIRATION=ON, CHECK_POLICY=ON
三,Create user
Users based on logins in master This is the most common type of user.
User based on a login based on a Windows user.
User based on a login based on a Windows group.
User based on a login using SQL Server authentication.
--Users based on logins in master CREATE USER user_name [ { FOR | FROM } LOGIN login_name ] [ WITH DEFAULT_SCHEMA = schema_name ] [ ; ]
user_name
Specifies the name by which the user is identified inside this database. user_name is a sysname. It can be up to 128 characters long.
login_name
Can be a login based on a Windows principal (user or group), or a login using SQL Server authentication. When this SQL Server login enters the database, it acquires the name and ID of the database user that is being created. When creating a login mapped from a Windows principal, use the format [<domainName>\<loginName>].
Create User 是创建User和Login之间的Mapping 关系,上文提到,这种Mapping 关系是通过SID来关联的,即Login访问数据库使用的User的SID和Login相同。
For Example
CREATE USER [UserName] FOR LOGIN [Domain\WindowsLoginName] --or [SQLLoginname] WITH DEFAULT_SCHEMA=[dbo] GO
从语法上看,当创建User时,UserName 和 LoginName 之间没有关系。如果使用Windows Login,那么UserName可以是LoginName,也可以是不是。
四,自动修复Orphaned users 问题
由于UserName 和 LoginName 之间没有关系,完全修复的可能性没有。但是,如果使用Windows验证,假设UserName 和 LoginName相同是可以的,那么可以使用Create Login from windows 创建Windows Login。
1,使用Alter User with login 重新创建Login 和 name之间的mapping 关系,Login 和 User的Mapping 关系是通过SID(security ID)来关联的。
ALTER USER userName WITH <set_item> [ ,...n ] <set_item> ::= NAME = newUserName | DEFAULT_SCHEMA = { schemaName | NULL } | LOGIN = loginName | PASSWORD = 'password' [ OLD_PASSWORD = 'oldpassword' ] | DEFAULT_LANGUAGE = { NONE | <lcid> | <language name> | <language alias> }
LOGIN =loginName
Re-maps a user to another login by changing the user's Security Identifier (SID) to match the login's SID.
Remarks
You can change the name of a user who is mapped to a Windows login or group only when the SID of the new user name matches the SID that is recorded in the database. This check helps prevent spoofing of Windows logins in the database.
The WITH LOGIN clause enables the remapping of a user to a different login. Only SQL users and Windows users (or groups) can be remapped. The WITH LOGIN clause cannot be used to change the type of user, such as changing a Windows account to a SQL Server login.
The name of the user will be automatically renamed to the login name if the following conditions are true.
The user is a Windows user.
The name is a Windows name (contains a backslash).
No new name was specified.
The current name differs from the login name.
Otherwise, the user will not be renamed unless the caller additionally invokes the NAME clause.
The name of a user mapped to a SQL Server login, a certificate, or an asymmetric key cannot contain the backslash character (\).
2,在重建login 和 user之间的mapping 关系时,user name 在满足一定条件时,能够被重命名为login name.
CREATE USER [username_xxx] FOR LOGIN [domain\xxxx] WITH DEFAULT_SCHEMA=[dbo] GO --user name [username_xxx] 被重命名为 [domain\yyyy] alter user [username_xxx] with login= [domain\yyyy] , DEFAULT_SCHEMA=[dbo] GO
3,自动修复Orphaned Users的script
DECLARE @username sysname DECLARE @sqlcmd NVARCHAR(max) = N'' IF OBJECT_ID(N'tempdb..#OrphanedUsers') IS NOT NULL DROP TABLE #OrphanedUsers CREATE TABLE #OrphanedUsers ( UserName sysname ) INSERT INTO #OrphanedUsers (UserName) SELECT [name] FROM sys.database_principals WHERE [type] IN (N'U', N'S') AND is_fixed_role = 0 AND [Name] NOT IN (N'dbo', N'guest', N'sys', N'INFORMATION_SCHEMA'); DECLARE cur_orphaned CURSOR LOCAL FORWARD_ONLY FAST_FORWARD READ_ONLY for SELECT UserName FROM #OrphanedUsers open cur_orphaned FETCH next FROM cur_orphaned into @username while @@fetch_status=0 BEGIN IF not exists (SELECT null FROM sys.server_principals WHERE [Name] = @username) BEGIN IF EXISTS(SELECT 1 FROM sys.database_principals WHERE [Name] = @username AND type_desc = N'WINDOWS_USER') BEGIN SET @sqlcmd = N'CREATE LOGIN [' + @username + N'] FROM WINDOWS' Exec(@sqlcmd) END ELSE -- type_desc = N'SQL_USER' BEGIN SET @sqlcmd = N'CREATE LOGIN [' + @username + N'] WITH PASSWORD = N''password''' Exec(@sqlcmd) END END SET @sqlcmd = N'ALTER USER [' + @username + N'] WITH LOGIN = [' + @username + N']' Exec(@sqlcmd) FETCH next FROM cur_orphaned into @username END CLOSE cur_orphaned DEALLOCATE cur_orphaned
五,guest
虽然术语“登录”和“用户”经常交换使用,但它们之间有很大的不同。登录用于用户身份验证,而数据库用户帐户用于数据库访问和权限验证。登录通过安全识别符 (SID) 与用户关联。访问 SQL Server 服务器需要登录。验证特定登录是否有效的过程称为“身份验证”。登录必须与 SQL Server 数据库用户相关联。您使用用户帐户控制数据库中执行的活动。如果数据库中不存在针对特定登录的用户帐户,使用该登录的用户即使能够连接到 SQL Server 服务器,也无法访问数据库。但是,该情形的唯一例外是当数据库包含“guest”用户帐户时。与用户帐户不关联的登录将被映射到 guest 用户。相反,如果存在数据库用户,但没有与其关联的登录,则该用户将无法登录到 SQL Server 服务器中。
参考文档:
Fixing orphaned database users in 2005 to 2012 – T-SQL Tuesday #025
Do you still use sp_change_users_login instead of ALTER USER UserName WITH LOGIN = UserName