Проверка, если логин SQL Server уже существует

176

Мне нужно проверить, существует ли конкретный логин на SQL Server, а если нет, то мне нужно добавить его.

Я нашел следующий код, чтобы фактически добавить логин в базу данных, но я хочу обернуть это в оператор IF (каким-то образом), чтобы проверить, существует ли логин первым.

CREATE LOGIN [myUsername] WITH PASSWORD=N'myPassword', 
DEFAULT_LANGUAGE=[us_english], 
CHECK_EXPIRATION=OFF, 
CHECK_POLICY=OFF 
GO

Я понимаю, что мне нужно опросить системную базу данных, но не уверен, с чего начать!

Бретт Ригби
источник
10
Это важный вопрос, но, как говорится, он, похоже, упускает важное различие: пользователь против логина. Потенциальный дубликат, с которым связался Джон, действительно связан с пользователями. Этот вопрос говорит «пользователь» в заголовке, но имеет дело с логинами в коде вопроса и в принятом ответе. Я отредактировал название и вопрос соответственно.
LarsH
1
Просто чтобы добавить к комментарию @LarsH, имена входа связаны с экземпляром сервера SQL, а пользователи - с определенной базой данных. Пользователи базы данных могут быть созданы из имен входа на сервер, поэтому они имеют доступ к определенной базе данных. См. Эту прекрасную статью и фактически всю серию, в которую она входит (Stariway to SQL Server Security)
Reversed Engineer

Ответы:

141

От сюда

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
Джонно Нолан
источник
6
Вы должны использовать QUOTENAME, чтобы предотвратить инъекцию SQL. Атакующий может передать @loginName какx] with password ''y'';\r\ndrop table foo;\r\n
Ремус Русану
2
Почему было необходимо создать инструкцию в виде строки и затем использовать sp_executesql, а не просто вводить ее напрямую CREATE LOGIN [@loginName] FROM ...? Прошу прощения за мое невежество, я хотел бы узнать ...
LarsH
4
@LarsH: создание оператора в виде строки необходимо, поскольку CREATE LOGIN не может использовать параметр для имени входа, для него требуется строковый литерал. Не уверен, почему это так, но я обнаружил, что это правда.
Джозеф Бонгаартс
@JosephBongaarts: ОК, спасибо. Я думаю, это похоже на имена таблиц в операторах SELECT. Возможно, идея состоит в том, чтобы уменьшить площадь поверхности, уязвимой для атак, хотя я не знаю, поможет ли это.
LarsH
1
Я думаю, что QUOTENAME()обойдется @loginName, а не все утверждение, и тогда вы сможете избавиться от ручных [и] разделителей вокруг @loginName.
brianary
288

Вот способ сделать это в SQL Server 2005 и более поздних версиях без использования устаревшего представления системных журналов:

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
Дерек Моррисон
источник
17
Лучший ответ, без участия динамического sql или устаревшего представления. Спасибо!
Каспер Леон Нильсен
7
В случае SQL Azure двумя целевыми таблицами являются sys.sql_logins и sys.sysusers - было бы неплохо включить это в ответ.
Бретт
Бесполезно, если ваш скрипт должен использовать переменную username.
Росс Прессер,
@ Дерек Моррисон, можем ли мы добавить еще одно условие для SID
AstroBoy
30

Как незначительное дополнение к этой теме, в общем, вы хотите избегать использования представлений, начинающихся с sys.sys *, поскольку Microsoft включает их только для обратной совместимости. Для вашего кода вы, вероятно, должны использовать sys.server_principals. Это предполагает, что вы используете SQL 2005 или выше.

Bomlin
источник
Проверено, работает и более актуально, чем другие ответы. +1 тебе тоже.
Дэвид
Да, с 2005 года Microsoft забрала прямой доступ к системным таблицам. Чтобы не сломать старый код, они включают в себя представления, которые имеют то же имя, что и старые таблицы. Тем не менее, они предназначены только для старого кода, и новый код должен использовать новые представления. В BOL выполните поиск по системным таблицам сопоставления, чтобы выяснить, что вам следует использовать.
Бомлин
11

Вы можете использовать встроенную функцию:

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

Худа
источник
Проголосовал за включение необязательных полей, отключающих политику и проверки срока действия.
Арчибальд
8

Попробуйте это (замените 'user' на фактическое имя пользователя):

IF NOT EXISTS(
SELECT name 
FROM [master].[sys].[syslogins]
WHERE NAME = 'user')

BEGIN 
    --create login here
END
Марк
источник
@Marc: Извините, но вы не правы. Таблица [syslogins] хранит логины, а таблица [sysusers] - пользователей.
абатищев
6

Это работает на SQL Server 2000.

use master
select count(*) From sysxlogins WHERE NAME = 'myUsername'

в SQL 2005 измените вторую строку на

select count(*) From syslogins WHERE NAME = 'myUsername'

Я не уверен насчет SQL 2008, но я предполагаю, что он будет таким же, как SQL 2005, и если нет, это должно дать вам представление о том, с чего начать.

Дэвид
источник
5

что именно вы хотите проверить на логин или пользователя? логин создается на уровне сервера, а пользователь создается на уровне базы данных, поэтому логин уникален на сервере

Кроме того, пользователь создается против входа в систему, пользователь без входа в систему является осиротевшим пользователем и бесполезен, так как вы не можете выполнить вход в SQL Server без входа в систему.

может тебе это нужно

проверить логин

select 'X' from master.dbo.syslogins where loginname=<username>

приведенный выше запрос возвращает 'X', если логин существует, иначе возвращает ноль

затем создайте логин

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
Akshita
источник
5

Чтобы избежать конфликта имен между логинами, ролями, пользователями и т. Д., Необходимо проверить typeстолбец в соответствии с документацией Microsoft sys.database_principals.

Для обработки специальных глав в именах пользователей и т. Д. Используйте 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>]
Хенрик Холмгаард Хойер
источник
-1

Сначала вы должны проверить существование логина, используя представление 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
M.Alaghemand
источник
1
Я не знаю - говоря, что «вы должны проверить существование входа в систему, используя представление syslogins», затем публикация кода, который не использует это представление, выглядит как проблема копирования и вставки. Кроме того, после первого утверждения строка «Затем вы должны проверить существование своей базы данных», используя параллельную форму, выглядит так, как будто вы просите кого-то проверить наличие базы данных, а не пользователя уровня БД. И вам нужно указать, что второй пакет должен быть запущен внутри целевой БД. В целом, это очень плохое объяснение. И поскольку вы добавили его через пять лет после того, как ответ с самым высоким голосом сказал то же самое, но лучше ...
Смеющийся Вергилий