Sprawdzanie, czy login SQL Server już istnieje


176

Muszę sprawdzić, czy określony login już istnieje na serwerze SQL, a jeśli nie, to muszę go dodać.

Znalazłem następujący kod, aby faktycznie dodać login do bazy danych, ale chcę zawrzeć to w instrukcji IF (w jakiś sposób), aby sprawdzić, czy login istnieje jako pierwszy.

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

Rozumiem, że muszę przeszukać bazę danych systemu, ale nie wiem, od czego zacząć!


10
To ważne pytanie, ale jak zostało sformułowane, wydaje się, że brakuje w nim ważnej różnicy: użytkownik a login. Potencjalny duplikat, do którego Jon odsyłał, naprawdę dotyczy użytkowników. To pytanie mówi w tytule „użytkownik”, ale dotyczy logowań w kodzie pytania i zaakceptowanej odpowiedzi. Odpowiednio zredagowałem tytuł i pytanie.
LarsH

1
Wystarczy dodać do komentarza @LarsH, loginy są powiązane z instancją serwera SQL, a użytkownicy są powiązani z określoną bazą danych. Użytkowników bazy danych można tworzyć z loginów serwera, dzięki czemu mają oni dostęp do określonej bazy danych. Zobacz ten doskonały artykuł, a właściwie całą serię, w której jest on częścią (Stariway to SQL Server Security)
Reversed Engineer

Odpowiedzi:


141

od tutaj

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
należy użyć QUOTENAME, aby zapobiec iniekcji sql. Atakujący może przekazać @loginName, takie jakx] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu

2
Dlaczego konieczne było utworzenie instrukcji jako ciągu, a następnie użycie sp_executesql, a nie tylko bezpośrednie wprowadzanie CREATE LOGIN [@loginName] FROM ...? Przepraszam za moją ignorancję, chciałbym się nauczyć ...
LarsH

4
@LarsH: Utworzenie instrukcji jako ciągu jest wymagane, ponieważ CREATE LOGIN nie może użyć parametru dla nazwy logowania, wymaga literału ciągu. Nie wiem, dlaczego tak jest, ale na własnej skórze przekonałem się, że to prawda.
Joseph Bongaarts

@JosephBongaarts: OK, dzięki. Wydaje mi się, że jest to podobne do nazw tabel w instrukcjach SELECT. Może chodzi o zmniejszenie powierzchni podatnej na ataki, chociaż nie wiem, czy to pomogłoby.
LarsH

1
Myślę, że QUOTENAME()omija się @loginNamecałe stwierdzenie, a nie całe stwierdzenie, a wtedy można pozbyć się instrukcji [i] ograniczników @loginName.
brianary

288

Oto sposób na zrobienie tego w programie SQL Server 2005 i nowszych wersjach bez korzystania z przestarzałego widoku syslogins:

IF NOT EXISTS 
    (SELECT name  
     FROM master.sys.server_principals
     WHERE name = 'LoginName')
BEGIN
    CREATE LOGIN [LoginName] WITH PASSWORD = N'password'
END

Widok server_principals jest używany zamiast sql_logins, ponieważ ten drugi nie wyświetla logowań systemu Windows.

Jeśli chcesz sprawdzić istnienie użytkownika w określonej bazie danych przed ich utworzeniem, możesz to zrobić:

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
Najlepsza odpowiedź, bez użycia dynamicznego SQL ani przestarzałego użycia widoku. Dzięki!
Casper Leon Nielsen

7
W przypadku SQL Azure dwie docelowe tabele to sys.sql_logins i sys.sysusers - warto uwzględnić to w odpowiedzi.
Brett,

Nie jest to przydatne, jeśli Twój skrypt musi używać zmiennej nazwy użytkownika.
Ross Presser

@Derek Morrison, czy możemy dodać jeszcze jeden warunek dla SID
AstroBoy

30

Jako drobny dodatek do tego wątku, generalnie chcesz uniknąć używania widoków rozpoczynających się od sys.sys *, ponieważ Microsoft uwzględnia je tylko w celu zachowania zgodności wstecznej. W swoim kodzie prawdopodobnie powinieneś użyć sys.server_principals. Zakładamy, że używasz SQL 2005 lub nowszego.


Przetestowane, działa i jest bardziej aktualne niż inne odpowiedzi. +1 również dla Ciebie.
David

Tak, w 2005 roku Microsoft odebrał bezpośredni dostęp do tabel systemowych. Aby nie złamać starego kodu, zawierają widoki, które miały taką samą nazwę jak stare tabele. Są one jednak przeznaczone tylko dla starszego kodu, a nowszy kod powinien używać nowych widoków. W BOL wyszukaj w Mapping System Tables, aby dowiedzieć się, czego powinieneś użyć.
Bomlin

11

Możesz skorzystać z wbudowanej funkcji:

SUSER_ID ( [ 'myUsername' ] )

przez

IF [value] IS NULL [statement]

lubić:

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


Głosowano za włączeniem opcjonalnych pól wyłączających zasady i sprawdzanie wygaśnięcia.
Archibald

8

Spróbuj tego (zamień „user” na rzeczywistą nazwę logowania):

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

BEGIN 
    --create login here
END

@Marc: Przepraszam, ale się mylisz. Tabela [syslogins] przechowuje loginy, a tabela [sysusers] przechowuje użytkowników.
abatishchev

6

Działa to na SQL Server 2000.

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

w SQL 2005 zmień drugą linię na

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

Nie jestem pewien co do SQL 2008, ale przypuszczam, że będzie to to samo, co SQL 2005, a jeśli nie, to powinno dać ci wyobrażenie, gdzie zacząć szukać.


5

co dokładnie chcesz sprawdzić dla loginu lub użytkownika? login jest tworzony na poziomie serwera, a użytkownik jest tworzony na poziomie bazy danych, więc login jest unikalny na serwerze

również tworzony jest użytkownik na podstawie loginu, użytkownik bez loginu jest użytkownikiem osieroconym i nie jest przydatny, ponieważ nie można przeprowadzić logowania do serwera sql bez logowania

może tego potrzebujesz

sprawdź logowanie

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

powyższe zapytanie zwraca „X”, jeśli login istnieje, w przeciwnym razie zwraca wartość null

następnie utwórz login

CREATE LOGIN <username> with PASSWORD=<password>

tworzy to login na serwerze sql, ale akceptuje tylko silne hasła

utwórz użytkownika w każdej bazie danych, do której chcesz się zalogować

CREATE USER <username> for login <username>

przypisać użytkownikowi prawa wykonywania

 GRANT EXECUTE TO <username>

MUSISZ MIEĆ uprawnienia SYSADMIN lub w skrócie powiedzieć „sa”

możesz napisać dla tego procedurę sql w bazie danych

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

W celu rozwiązania konfliktu nazw między loginami, rolami, użytkownikami itp. Należy sprawdzić typekolumnę zgodnie z dokumentacją Microsoft sys.database_principals

Aby obsłużyć specjalne znaki w nazwach użytkowników itp., Użyj odpowiednio N'<name>'i [<name>].

Utwórz login

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>

Utwórz użytkownika bazy danych

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>]

Utwórz rolę bazy danych

USE <databasename>
IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE 
[name] = N'<rolename>' and Type = 'R')
    CREATE ROLE [<rolename>]

Dodaj użytkownika do roli

USE <databasename>
EXEC sp_addrolemember N'<rolename>', N'<username>'

Przyznaj prawa roli

USE <databasename>
GRANT SELECT ON [<tablename>] TO [<rolename>]
GRANT UPDATE ON [<tablename>] ([<columnname>]) TO [<rolename>]
GRANT EXECUTE ON [<procedurename>] TO [<rolename>]


-1

Najpierw musisz sprawdzić istnienie logowania za pomocą widoku syslogins:

IF NOT EXISTS 
    (SELECT name  
     FROM master.sys.server_principals
     WHERE name = 'YourLoginName')
BEGIN
    CREATE LOGIN [YourLoginName] WITH PASSWORD = N'password'
END

Następnie musisz sprawdzić istnienie bazy danych:

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
Nie wiem - mówienie, że „musisz sprawdzić istnienie logowania za pomocą widoku syslogins”, a następnie wysłanie kodu, który nie używa tego widoku, wygląda jak problem z kopiowaniem i wklejaniem. Również po pierwszej instrukcji wiersz „Następnie musisz sprawdzić istnienie bazy danych”, używając formularza równoległego, wygląda tak, jakbyś prosił kogoś o sprawdzenie istnienia bazy danych, a nie użytkownika na poziomie bazy danych. I musisz określić, że druga partia musi zostać uruchomiona w docelowej bazie danych. Ogólnie jest to po prostu bardzo słabe wyjaśnienie. A ponieważ dodałeś to pięć lat po najwyższej głosowanej odpowiedzi, powiedziałeś to samo, ale lepiej ...
Laughing Vergil
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.