Перевірка наявності входу на SQL Server


176

Мені потрібно перевірити, чи певний логін вже існує на SQL сервері, а якщо його немає, то мені потрібно додати його.

Я знайшов наступний код, щоб насправді додати логін до бази даних, але я хочу обернути це в операторі IF (якось), щоб перевірити, чи логін спочатку існує.

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

Я розумію, що мені потрібно допитати системну базу даних, але не впевнений, з чого почати!


10
Це важливе питання, але, як це висловлено у фразі, начебто пропускається важлива відмінність: користувач проти входу. Потенційний дублікат, з яким пов’язаний Джон, насправді стосується користувачів. Це запитання зазначає "користувач" у заголовку, але має справу з логінами в коді запитання та у прийнятій відповіді. Я відповідно редагував заголовок та запитання.
LarsH

1
Просто для додання коментаря @LarsH, реєстрації асоціюються з екземпляром сервера SQL, а користувачі пов’язані з певною базою даних. Користувачі баз даних можуть бути створені з входу в сервер, щоб вони мали доступ до певної бази даних. Дивіться цю чудову статтю, і фактично ціла серія, до якої вона входить (Старівей до безпеки SQL Server)
інженер, що

Відповіді:


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.
бріанарій

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 - можливо, було б добре включити це у відповідь.
Бретт

Не корисно, якщо у вашому сценарії потрібно використовувати змінне ім’я користувача.
Росс

@Derek Morrison ми можемо додати ще одну умову для SID
AstroBoy

30

Як незначне доповнення до цього потоку, загалом ви хочете уникати використання поглядів, які починаються з sys.sys *, оскільки Microsoft включає їх лише для зворотної сумісності. Для свого коду, ймовірно, слід використовувати sys.server_principals. Це за умови, що ви використовуєте SQL 2005 або новішої версії.


Перевірено, працює і більш актуально, ніж інші відповіді. +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

Спробуйте це (замініть "користувача" фактичним іменем для входу):

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

BEGIN 
    --create login here
END

@Marc: Вибачте, але ви помиляєтесь. Таблиця [syslogins] зберігає логіни, а table [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 без входу.

можливо, вам це потрібно

чек для входу

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

вищезазначений запит повертає "X", якщо логін існує інше return null

потім створіть логін

CREATE LOGIN <username> with PASSWORD=<password>

це створює логін на сервері sql. але він приймає лише надійні паролі

створити користувача у кожній базі даних, в яку ви хочете ввійти як

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

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

1
Я не знаю, кажучи, що "ви повинні перевірити існування входу за допомогою перегляду syslogins", тоді розміщення коду, який не використовує цей погляд, виглядає як проблема копіювання та вставки. Крім того, після першого твердження рядок "Тоді ви повинні перевірити наявність своєї бази даних", використовуючи паралельну форму, виглядає так, що ви просите когось перевірити наявність бази даних, а не користувача рівня БД. І вам потрібно вказати, що другу партію потрібно запустити всередині цільової БД. Загалом, це лише дуже бідне пояснення. А оскільки ви додали це через п’ять років після того, як найвисокоцінніша відповідь сказала те саме, але краще ...
Сміється Вергілій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.