检查 SQL Server 登录是不是已存在
Posted
技术标签:
【中文标题】检查 SQL Server 登录是不是已存在【英文标题】:Checking if a SQL Server login already exists检查 SQL Server 登录是否已存在 【发布时间】:2010-11-25 15:38:57 【问题描述】:我需要检查 SQL Server 上是否已经存在特定登录,如果不存在,则需要添加它。
我找到了以下代码来实际将登录名添加到数据库中,但我想将其包装在一个 IF 语句中(以某种方式)以首先检查登录名是否存在。
CREATE LOGIN [myUsername] WITH PASSWORD=N'myPassword',
DEFAULT_LANGUAGE=[us_english],
CHECK_EXPIRATION=OFF,
CHECK_POLICY=OFF
GO
我知道我需要查询系统数据库,但不知道从哪里开始!
【问题讨论】:
这是一个重要的问题,但正如措辞所言,它似乎忽略了一个重要的区别:用户与登录。 Jon 链接到的潜在副本似乎与用户有关。此问题在标题中显示“用户”,但在问题代码和接受的答案中处理登录。我相应地编辑了标题和问题。 只是添加到@LarsH 的评论中,logins 与 SQL 服务器实例相关联,而 users 与特定数据库相关联。可以从服务器登录创建数据库用户,因此他们可以访问特定数据库。请参阅this excellent article,实际上它是整个系列的一部分(Stariway 到 SQL Server 安全性) 【参考方案1】:开始 SQL 2016:
DROP USER IF EXISTS [userName]
CREATE USER [userName] FOR LOGIN [loginName]
【讨论】:
【参考方案2】:为了处理登录名、角色、用户等之间的命名冲突,您应该根据Microsoft sys.database_principals documentation检查type
列
为了处理用户名等中的特殊字符,请相应地使用N'<name>'
和[<name>]
。
创建登录
USE MASTER
IF NOT EXISTS (SELECT 1 FROM master.sys.server_principals WHERE
[name] = N'<loginname>' and [type] IN ('C','E', 'G', 'K', 'S', 'U'))
CREATE LOGIN [<loginname>] <further parameters>
创建数据库用户
USE [<databasename>]
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE
[name] = N'<username>' and [type] IN ('C','E', 'G', 'K', 'S', 'U'))
CREATE USER [<username>] FOR LOGIN [<loginname>]
创建数据库角色
USE [<databasename>]
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE
[name] = N'<rolename>' and Type = 'R')
CREATE ROLE [<rolename>]
将用户添加到角色
USE [<databasename>]
EXEC sp_addrolemember N'<rolename>', N'<username>'
授予角色权限
USE [<databasename>]
GRANT SELECT ON [<tablename>] TO [<rolename>]
GRANT UPDATE ON [<tablename>] ([<columnname>]) TO [<rolename>]
GRANT EXECUTE ON [<procedurename>] TO [<rolename>]
SQL 在 SQL Server 2005、2008、2008 R2、2014、2016、2017、2019 上测试
【讨论】:
【参考方案3】:这是针对 Azure SQL 的:
IF (EXISTS(SELECT TOP 1 1 FROM sys.sql_logins WHERE [name] = '<login>'))
DROP LOGIN [<login>];
来源:How to check whether database user already exists in Azure SQL Database
【讨论】:
【参考方案4】:你可以使用内置函数:
SUSER_ID ( [ 'myUsername' ] )
通过
IF [value] IS NULL [statement]
喜欢:
IF SUSER_ID (N'myUsername') IS NULL
CREATE LOGIN [myUsername] WITH PASSWORD=N'myPassword',
DEFAULT_LANGUAGE=[us_english],
CHECK_EXPIRATION=OFF,
CHECK_POLICY=OFF
GO
https://technet.microsoft.com/en-us/library/ms176042(v=sql.110).aspx
【讨论】:
这个解决方案很棒,因为它不需要 ALTER ANY LOGIN 权限,而其他所有的都需要。在我的情况下,不可能授予我们的工具权限以查看数据库中的所有登录,但 SUSER_ID('loginName') 仍可用于测试登录是否已存在。谢谢!【参考方案5】:来自here
If not Exists (select loginname from master.dbo.syslogins
where name = @loginName and dbname = 'PUBS')
Begin
Select @SqlStatement = 'CREATE LOGIN ' + QUOTENAME(@loginName) + '
FROM WINDOWS WITH DEFAULT_DATABASE=[PUBS], DEFAULT_LANGUAGE=[us_english]')
EXEC sp_executesql @SqlStatement
End
【讨论】:
你应该使用 QUOTENAME 来防止 sql 注入。攻击者可以通过@loginName 像x] with password ''y'';\r\ndrop table foo;\r\n
为什么要创建一个语句作为字符串然后使用sp_executesql,而不是直接输入CREATE LOGIN [@loginName] FROM ...
?请原谅我的无知,我想学习...
@LarsH:需要将语句创建为字符串,因为 CREATE LOGIN 不能使用参数作为登录名,它需要字符串文字。不知道为什么会这样,但我发现这是真的。
我认为QUOTENAME()
围绕@loginName
,而不是整个声明,然后您可以摆脱@loginName
周围的手动[ 和] 分隔符。
syslogins 视图已弃用【参考方案6】:
首先您必须使用 syslogins 视图检查登录是否存在:
IF NOT EXISTS
(SELECT name
FROM master.sys.server_principals
WHERE name = 'YourLoginName')
BEGIN
CREATE LOGIN [YourLoginName] WITH PASSWORD = N'password'
END
然后你必须检查你的数据库是否存在:
USE your_dbname
IF NOT EXISTS
(SELECT name
FROM sys.database_principals
WHERE name = 'your_dbname')
BEGIN
CREATE USER [your_dbname] FOR LOGIN [YourLoginName]
END
【讨论】:
我不知道 - 说“您必须使用 syslogins 视图检查登录是否存在”,然后发布不使用该视图的代码看起来像是复制和粘贴问题。此外,在第一条语句之后,“那么你必须检查你的数据库是否存在”这一行,使用并行形式,看起来你是在要求某人检查数据库的存在,而不是数据库级别的用户。并且您需要指定第二批需要在目标数据库中运行。总的来说,这只是一个非常糟糕的解释。而且由于您在获得最高投票的答案五年后添加了它,但更好......【参考方案7】:您到底想检查登录名或用户什么? 登录是在服务器级别创建的,而用户是在数据库级别创建的,因此登录在服务器中是唯一的
另外一个用户是针对登录创建的,没有登录的用户是一个孤立的用户并且没有用,因为你不能在没有登录的情况下执行 sql server 登录
也许你需要这个
检查登录
select 'X' from master.dbo.syslogins where loginname=<username>
如果登录存在,上述查询返回'X',否则返回null
然后创建一个登录
CREATE LOGIN <username> with PASSWORD=<password>
这会在 sql server 中创建一个登录名。但它只接受强密码
在您要登录的每个数据库中创建一个用户
CREATE USER <username> for login <username>
为用户分配执行权限
GRANT EXECUTE TO <username>
您必须拥有 SYSADMIN 权限或简称为“sa”
您可以在数据库上为此编写一个 sql 过程
create proc createuser
(
@username varchar(50),
@password varchar(50)
)
as
begin
if not exists(select 'X' from master.dbo.syslogins where loginname=@username)
begin
if not exists(select 'X' from sysusers where name=@username)
begin
exec('CREATE LOGIN '+@username+' WITH PASSWORD='''+@password+'''')
exec('CREATE USER '+@username+' FOR LOGIN '+@username)
exec('GRANT EXECUTE TO '+@username)
end
end
end
【讨论】:
【参考方案8】:以下是在 SQL Server 2005 及更高版本中执行此操作的方法,无需使用已弃用的 syslogins 视图:
IF NOT EXISTS
(SELECT name
FROM master.sys.server_principals
WHERE name = 'LoginName')
BEGIN
CREATE LOGIN [LoginName] WITH PASSWORD = N'password'
END
使用 server_principals 视图代替 sql_logins,因为后者不列出 Windows 登录。
如果您需要在创建之前检查特定数据库中的用户是否存在,那么您可以这样做:
USE your_db_name
IF NOT EXISTS
(SELECT name
FROM sys.database_principals
WHERE name = 'Bob')
BEGIN
CREATE USER [Bob] FOR LOGIN [Bob]
END
【讨论】:
最佳答案,不涉及动态 sql,也没有任何已弃用的视图用法。谢谢! 在 SQL Azure 的情况下,两个目标表是 sys.sql_logins 和 sys.sysusers ——在答案中包含这个可能会很好。 如果您的脚本需要使用可变用户名,则无用。 @Derek Morrison 我们可以为 SID 添加一个条件【参考方案9】:作为此线程的一个小补充,通常您希望避免使用以 sys.sys* 开头的视图,因为 Microsoft 仅包含它们是为了向后兼容。对于您的代码,您可能应该使用 sys.server_principals。这是假设您使用的是 SQL 2005 或更高版本。
【讨论】:
经过测试,有效,并且比其他答案更新。也为你 +1。 是的,2005 年微软取消了对系统表的直接访问。为了避免破坏旧代码,它们包含与旧表同名的视图。但是,它们仅适用于较旧的代码,而较新的代码应使用新视图。在 BOL 中,对 Mapping System Tables 进行搜索以找出您应该使用的内容。【参考方案10】:试试这个(用实际登录名替换“用户”):
IF NOT EXISTS(
SELECT name
FROM [master].[sys].[syslogins]
WHERE NAME = 'user')
BEGIN
--create login here
END
【讨论】:
@Marc:对不起,你错了。表 [syslogins] 保存登录名,表 [sysusers] 保存用户。【参考方案11】:这适用于 SQL Server 2000。
use master
select count(*) From sysxlogins WHERE NAME = 'myUsername'
在 SQL 2005 上,将第 2 行更改为
select count(*) From syslogins WHERE NAME = 'myUsername'
我不确定 SQL 2008,但我猜它会与 SQL 2005 相同,如果不是,这应该让您知道从哪里开始寻找。
【讨论】:
以上是关于检查 SQL Server 登录是不是已存在的主要内容,如果未能解决你的问题,请参考以下文章