Überprüfen, ob bereits eine SQL Server-Anmeldung vorhanden ist

176

Ich muss überprüfen, ob auf dem SQL Server bereits ein bestimmtes Login vorhanden ist. Wenn dies nicht der Fall ist, muss ich es hinzufügen.

Ich habe den folgenden Code gefunden, um die Anmeldung tatsächlich zur Datenbank hinzuzufügen, aber ich möchte dies (irgendwie) in eine IF-Anweisung einschließen, um zu überprüfen, ob die Anmeldung zuerst vorhanden ist.

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

Ich verstehe, dass ich eine Systemdatenbank abfragen muss, bin mir aber nicht sicher, wo ich anfangen soll!

Brett Rigby
quelle
10
Dies ist eine wichtige Frage, aber wie formuliert, scheint eine wichtige Unterscheidung zu fehlen: Benutzer vs. Login. Das potenzielle Duplikat, mit dem Jon verlinkt hat, scheint sich wirklich um Benutzer zu handeln. Diese Frage sagt im Titel "Benutzer", befasst sich jedoch mit Anmeldungen im Fragencode und in der akzeptierten Antwort. Ich habe den Titel und die Frage entsprechend bearbeitet.
LarsH
1
Nur um den Kommentar von @LarsH zu ergänzen, werden Anmeldungen einer SQL Server-Instanz und Benutzer einer bestimmten Datenbank zugeordnet. Datenbankbenutzer können aus Serveranmeldungen erstellt werden, sodass sie Zugriff auf eine bestimmte Datenbank haben. Lesen Sie diesen ausgezeichneten Artikel und tatsächlich die gesamte Serie, zu der er gehört (Stariway to SQL Server Security)
Reversed Engineer

Antworten:

141

Von hier aus

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
Johnno Nolan
quelle
6
Sie sollten QUOTENAME verwenden, um eine SQL-Injektion zu verhindern. Angreifer können einen @loginName wiex] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu
2
Warum war es notwendig, eine Anweisung als Zeichenfolge zu erstellen und dann sp_executesql zu verwenden, anstatt nur direkt einzugeben CREATE LOGIN [@loginName] FROM ...? Verzeihen Sie meine Unwissenheit, ich würde gerne lernen ...
LarsH
4
@LarsH: Das Erstellen der Anweisung als Zeichenfolge ist erforderlich, da CREATE LOGIN keinen Parameter für den Anmeldenamen verwenden kann, sondern ein Zeichenfolgenliteral benötigt. Ich bin mir nicht sicher, warum das so ist, aber ich habe auf die harte Tour herausgefunden, dass es wahr ist.
Joseph Bongaarts
@ JosephBongaarts: OK, danke. Ich denke, es ist wie Tabellennamen in SELECT-Anweisungen. Vielleicht besteht die Idee darin, die für Angriffe anfällige Oberfläche zu verringern, obwohl ich nicht weiß, dass dies helfen würde.
LarsH
1
Ich denke, es QUOTENAME()geht herum @loginName, nicht die ganze Aussage, und dann können Sie die manuellen [und] Trennzeichen loswerden @loginName.
Brian
288

In SQL Server 2005 und höher können Sie dies folgendermaßen tun, ohne die veraltete Ansicht "Syslogins" zu verwenden:

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

Die Ansicht server_principals wird anstelle von sql_logins verwendet, da letztere keine Windows-Anmeldungen auflistet.

Wenn Sie vor dem Erstellen überprüfen müssen, ob ein Benutzer in einer bestimmten Datenbank vorhanden ist, können Sie Folgendes tun:

USE your_db_name

IF NOT EXISTS
    (SELECT name
     FROM sys.database_principals
     WHERE name = 'Bob')
BEGIN
    CREATE USER [Bob] FOR LOGIN [Bob] 
END
Derek Morrison
quelle
17
Beste Antwort, weder dynamisches SQL noch veraltete Ansichtsnutzung. Vielen Dank!
Casper Leon Nielsen
7
Im Fall von SQL Azure sind die beiden Zieltabellen sys.sql_logins und sys.sysusers - möglicherweise ist es hilfreich, dies in die Antwort aufzunehmen.
Brett
Nicht nützlich, wenn Ihr Skript einen variablen Benutzernamen verwenden muss.
Ross Presser
@Derek Morrison können wir eine weitere Bedingung für SID hinzufügen
AstroBoy
30

Als geringfügige Ergänzung zu diesem Thread möchten Sie im Allgemeinen vermeiden, die Ansichten zu verwenden, die mit sys.sys * beginnen, da Microsoft sie nur aus Gründen der Abwärtskompatibilität einschließt. Für Ihren Code sollten Sie wahrscheinlich sys.server_principals verwenden. Dies setzt voraus, dass Sie SQL 2005 oder höher verwenden.

Bomlin
quelle
Getestet, funktioniert und aktueller als die anderen Antworten. +1 auch für dich.
David
Ja, mit 2005 hat Microsoft den direkten Zugriff auf die Systemtabellen weggenommen. Um zu verhindern, dass alter Code beschädigt wird, enthalten sie Ansichten, die denselben Namen wie die alten Tabellen haben. Sie sind jedoch nur für älteren Code gedacht, und neuerer Code sollte die neuen Ansichten verwenden. Führen Sie in BOL eine Suche in Mapping-Systemtabellen durch, um herauszufinden, was Sie verwenden sollten.
Bomlin
11

Sie können die eingebaute Funktion verwenden:

SUSER_ID ( [ 'myUsername' ] )

über

IF [value] IS NULL [statement]

mögen:

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

Hüda
quelle
Upvoted für die Aufnahme optionaler Felder, die Richtlinien- und Ablaufprüfungen deaktivieren.
Archibald
8

Versuchen Sie dies (ersetzen Sie 'Benutzer' durch den tatsächlichen Anmeldenamen):

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

BEGIN 
    --create login here
END
Marc
quelle
@ Marc: Entschuldigung, aber du liegst falsch. Tabelle [syslogins] enthält Anmeldungen und Tabelle [sysusers] enthält Benutzer.
Abatishchev
6

Dies funktioniert unter SQL Server 2000.

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

Ändern Sie in SQL 2005 die 2. Zeile in

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

Ich bin mir bei SQL 2008 nicht sicher, aber ich vermute, dass es mit SQL 2005 identisch sein wird. Wenn nicht, sollte dies Ihnen eine Vorstellung davon geben, wo Sie anfangen sollen zu suchen.

David
quelle
5

Was genau möchten Sie für Login oder Benutzer überprüfen? Auf Serverebene wird eine Anmeldung erstellt, und auf Datenbankebene wird ein Benutzer erstellt, sodass eine Anmeldung auf dem Server eindeutig ist

Außerdem wird ein Benutzer für eine Anmeldung erstellt. Ein Benutzer ohne Anmeldung ist ein verwaister Benutzer und nicht nützlich, da keine SQL Server-Anmeldung ohne Anmeldung durchgeführt werden kann

Vielleicht brauchst du das

auf Login prüfen

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

Die obige Abfrage gibt 'X' zurück, wenn die Anmeldung vorhanden ist. Andernfalls wird null zurückgegeben

Erstellen Sie dann ein Login

CREATE LOGIN <username> with PASSWORD=<password>

Dadurch wird ein Login in SQL Server erstellt, es werden jedoch nur sichere Kennwörter akzeptiert

Erstellen Sie in jeder Datenbank, unter der Sie sich anmelden möchten, einen Benutzer

CREATE USER <username> for login <username>

Weisen Sie dem Benutzer Ausführungsrechte zu

 GRANT EXECUTE TO <username>

SIE MÜSSEN SYSADMIN-Berechtigungen haben oder kurz 'sa' sagen

Sie können dafür eine SQL-Prozedur in eine Datenbank schreiben

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
quelle
5

Um Namenskonflikte zwischen Anmeldungen, Rollen, Benutzern usw. typezu vermeiden, sollten Sie die Spalte gemäß der Dokumentation zu Microsoft sys.database_principals überprüfen

Verwenden Sie N'<name>'und [<name>]entsprechend , um mit speziellen Zeichen in Benutzernamen usw. umzugehen .

Login erstellen

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>

Datenbankbenutzer erstellen

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

Datenbankrolle erstellen

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

Benutzer zur Rolle hinzufügen

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

Gewährung von Rollenrechten

USE <databasename>
GRANT SELECT ON [<tablename>] TO [<rolename>]
GRANT UPDATE ON [<tablename>] ([<columnname>]) TO [<rolename>]
GRANT EXECUTE ON [<procedurename>] TO [<rolename>]
Henrik Holmgaard Høyer
quelle
-1

Zuerst müssen Sie die Existenz der Anmeldung mithilfe der Syslogins-Ansicht überprüfen:

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

Dann müssen Sie Ihre Datenbankexistenz überprüfen:

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
quelle
1
Ich weiß nicht - zu sagen, dass "Sie das Vorhandensein der Anmeldung mithilfe der Syslogins-Ansicht überprüfen müssen", und dass das Posten von Code, der diese Ansicht nicht verwendet, wie ein Problem beim Kopieren und Einfügen aussieht. Nach der ersten Anweisung sieht die Zeile "Dann müssen Sie Ihre Datenbankexistenz überprüfen" in paralleler Form so aus, als würden Sie jemanden bitten, die Existenz einer Datenbank zu überprüfen, nicht eines Benutzers auf DB-Ebene. Außerdem müssen Sie angeben, dass der zweite Stapel in der Ziel-DB ausgeführt werden muss. Insgesamt ist dies nur eine sehr schlechte Erklärung. Und da Sie es fünf Jahre nach der am höchsten bewerteten Antwort hinzugefügt haben, wurde dasselbe gesagt, aber besser ...
Lachender Vergil