Vérifier si une connexion SQL Server existe déjà

176

J'ai besoin de vérifier si une connexion spécifique existe déjà sur le serveur SQL, et si ce n'est pas le cas, je dois l'ajouter.

J'ai trouvé le code suivant pour ajouter réellement la connexion à la base de données, mais je veux l'envelopper dans une instruction IF (en quelque sorte) pour vérifier si la connexion existe en premier.

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

Je comprends que j'ai besoin d'interroger une base de données système, mais je ne sais pas par où commencer!

Brett Rigby
la source
10
C'est une question importante, mais telle qu'elle est formulée, il semble manquer une distinction importante: utilisateur vs connexion. Le doublon potentiel auquel Jon a lié semble vraiment concerner les utilisateurs. Cette question dit «utilisateur» dans le titre, mais traite des connexions dans le code de la question et dans la réponse acceptée. J'ai édité le titre et la question en conséquence.
LarsH
1
Juste pour ajouter au commentaire de @LarsH, les connexions sont associées à une instance de serveur SQL et les utilisateurs sont associés à une base de données spécifique. Les utilisateurs de la base de données peuvent être créés à partir des connexions serveur, afin qu'ils aient accès à une base de données spécifique. Voir cet excellent article et en fait toute la série dont il fait partie (Stariway to SQL Server Security)
Reversed Engineer

Réponses:

141

D' ici

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
la source
6
vous devez utiliser QUOTENAME pour empêcher l'injection de sql. L'attaquant peut passer un @loginName commex] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu
2
Pourquoi était-il nécessaire de créer une instruction sous forme de chaîne puis d'utiliser sp_executesql, plutôt que de simplement entrer directement CREATE LOGIN [@loginName] FROM ...? Pardonnez mon ignorance, j'aimerais apprendre ...
LarsH
4
@LarsH: La création de l'instruction sous forme de chaîne est obligatoire car CREATE LOGIN ne peut pas utiliser de paramètre pour le nom de connexion, elle nécessite une chaîne littérale. Je ne sais pas pourquoi, mais j'ai découvert à la dure que c'était vrai.
Joseph Bongaarts
@JosephBongaarts: OK, merci. Je suppose que c'est comme les noms de table dans les instructions SELECT. Peut-être que l'idée est de réduire la surface vulnérable aux attaques, même si je ne sais pas si cela aiderait.
LarsH
1
Je pense que ça QUOTENAME()tourne autour @loginName, pas toute la déclaration, et alors vous pouvez vous débarrasser des délimiteurs manuels [et] @loginName.
brianary
288

Voici un moyen de le faire dans SQL Server 2005 et versions ultérieures sans utiliser la vue syslogins obsolète:

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

La vue server_principals est utilisée à la place de sql_logins car ce dernier ne répertorie pas les connexions Windows.

Si vous devez vérifier l'existence d'un utilisateur dans une base de données particulière avant de le créer, vous pouvez le faire:

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
la source
17
Meilleure réponse, aucun SQL dynamique impliqué, ni aucune utilisation de vue obsolète. Merci!
Casper Leon Nielsen
7
Dans le cas de SQL Azure, les deux tables cibles sont sys.sql_logins et sys.sysusers - il serait peut-être intéressant de l'inclure dans la réponse.
Brett
Pas utile si votre script doit utiliser un nom d'utilisateur variable.
Ross Presser
@Derek Morrison pouvons-nous ajouter une condition supplémentaire pour SID
AstroBoy
30

En tant qu'ajout mineur à ce fil, vous souhaitez généralement éviter d'utiliser les vues qui commencent par sys.sys * car Microsoft ne les inclut que pour la compatibilité descendante. Pour votre code, vous devriez probablement utiliser sys.server_principals. Cela suppose que vous utilisez SQL 2005 ou supérieur.

Bomlin
la source
Testé, fonctionne et plus actuel que les autres réponses. +1 pour vous également.
David le
Oui, avec 2005, Microsoft a supprimé l'accès direct aux tables système. Pour éviter de casser l'ancien code, ils incluent des vues qui portaient le même nom que les anciennes tables. Cependant, ils sont uniquement destinés au code plus ancien et au code plus récent si vous utilisez les nouvelles vues. Dans BOL, effectuez une recherche sur les tables système de mappage pour savoir ce que vous devez utiliser.
Bomlin le
11

Vous pouvez utiliser la fonction intégrée:

SUSER_ID ( [ 'myUsername' ] )

via

IF [value] IS NULL [statement]

comme:

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
la source
Voté pour l'inclusion de champs facultatifs désactivant la politique et les contrôles d'expiration.
Archibald
8

Essayez ceci (remplacez «utilisateur» par le nom de connexion réel):

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

BEGIN 
    --create login here
END
Marc
la source
@Marc: Désolé mais vous vous trompez. Table [syslogins] conserve les connexions et la table [sysusers] garde les utilisateurs.
abatishchev
6

Cela fonctionne sur SQL Server 2000.

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

sur SQL 2005, remplacez la deuxième ligne par

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

Je ne suis pas sûr de SQL 2008, mais je suppose que ce sera le même que SQL 2005 et sinon, cela devrait vous donner une idée de l'endroit où commencer à chercher.

David
la source
5

que voulez-vous exactement vérifier la connexion ou l'utilisateur? une connexion est créée au niveau du serveur et un utilisateur est créé au niveau de la base de données de sorte qu'une connexion est unique dans le serveur

également un utilisateur est créé contre une connexion, un utilisateur sans connexion est un utilisateur orphelin et n'est pas utile car vous ne pouvez pas effectuer de connexion au serveur SQL sans connexion

peut-être que tu en as besoin

vérifier la connexion

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

la requête ci-dessus renvoie 'X' si la connexion existe sinon retourne null

puis créez un login

CREATE LOGIN <username> with PASSWORD=<password>

cela crée une connexion au serveur sql. mais il n'accepte que les mots de passe forts

créer un utilisateur dans chaque base de données que vous souhaitez pour vous connecter en tant que

CREATE USER <username> for login <username>

attribuer des droits d'exécution à l'utilisateur

 GRANT EXECUTE TO <username>

VOUS DEVEZ AVOIR les autorisations SYSADMIN ou dire «sa» pour faire court

vous pouvez écrire une procédure SQL pour cela sur une base de données

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
la source
5

Afin de résoudre les conflits de noms entre les connexions, les rôles, les utilisateurs, etc., vous devez vérifier la typecolonne conformément à la documentation Microsoft sys.database_principals

Afin de gérer les chapitres spéciaux dans les noms d'utilisateur, etc., utilisez N'<name>'et en [<name>]conséquence.

Créer une connexion

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>

Créer un utilisateur de base de données

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

Créer un rôle de base de données

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

Ajouter un utilisateur au rôle

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

Accorder des droits au rôle

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
la source
-1

Vous devez d'abord vérifier l'existence de la connexion à l'aide de la vue syslogins:

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

Ensuite, vous devez vérifier l'existence de votre base de données:

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
la source
1
Je ne sais pas - dire que "vous devez vérifier l'existence de connexion en utilisant la vue syslogins", puis publier du code qui n'utilise pas cette vue ressemble à un problème de copier-coller. De plus, après la première déclaration, la ligne "Ensuite, vous devez vérifier l'existence de votre base de données", en utilisant un formulaire parallèle, donne l'impression que vous demandez à quelqu'un de vérifier l'existence d'une base de données, pas à un utilisateur de niveau DB. Et vous devez spécifier que le deuxième lot doit être exécuté dans la base de données cible. Dans l'ensemble, ce n'est qu'une très mauvaise explication. Et puisque vous l'avez ajouté cinq ans après que la réponse la plus élevée ait dit la même chose, mais mieux ...
Laughing Vergil