Verifica se esiste già un accesso a SQL Server


176

Devo verificare se esiste già un accesso specifico su SQL Server e, in caso contrario, devo aggiungerlo.

Ho trovato il seguente codice per aggiungere effettivamente il login al database, ma voglio racchiuderlo in un'istruzione IF (in qualche modo) per verificare se il login esiste prima.

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

Capisco che devo interrogare un database di sistema, ma non sono sicuro da dove cominciare!


10
Questa è una domanda importante, ma come formulata, sembra mancare una distinzione importante: utente vs. login. Il potenziale duplicato che Jon ha collegato sembra davvero riguardare gli utenti. Questa domanda indica "utente" nel titolo, ma si occupa degli accessi nel codice della domanda e nella risposta accettata. Ho modificato il titolo e la domanda di conseguenza.
LarsH

1
Solo per aggiungere al commento di @LarsH, gli accessi sono associati a un'istanza del server SQL e gli utenti sono associati a un database specifico. Gli utenti del database possono essere creati dagli accessi al server, quindi hanno accesso a un database specifico. Vedi questo eccellente articolo e in effetti l'intera serie di cui fa parte (Stariway to SQL Server Security)
Ingegnere invertito

Risposte:


141

Da qui

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
dovresti usare QUOTENAME per prevenire l'iniezione sql. L'attaccante può passare un @loginName comex] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu,

2
Perché è stato necessario creare un'istruzione come stringa e quindi utilizzare sp_executesql, anziché inserirla direttamente CREATE LOGIN [@loginName] FROM ...? Perdonate la mia ignoranza, mi piacerebbe imparare ...
LarsH,

4
@LarsH: la creazione dell'istruzione come stringa è necessaria perché CREATE LOGIN non può utilizzare un parametro per il nome di accesso, richiede una stringa letterale. Non sono sicuro del perché, ma ho scoperto che è vero.
Joseph Bongaarts,

@JosephBongaarts: OK, grazie. Immagino sia come i nomi delle tabelle nelle istruzioni SELECT. Forse l'idea è di ridurre la superficie vulnerabile agli attacchi, anche se non so che sarebbe di aiuto.
LarsH,

1
Penso che QUOTENAME()vada in giro @loginName, non l'intera affermazione, e quindi puoi sbarazzarti dei delimitatori manuali [e] in giro @loginName.
brianary

288

Ecco un modo per eseguire questa operazione in SQL Server 2005 e versioni successive senza utilizzare la vista obsoleta dei syslogins:

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

La vista server_principals viene utilizzata al posto di sql_logins poiché quest'ultima non elenca gli accessi a Windows.

Se è necessario verificare l'esistenza di un utente in un determinato database prima di crearlo, è possibile effettuare ciò:

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
Migliore risposta, nessun sql dinamico coinvolto, né alcun utilizzo obsoleto della vista. Grazie!
Casper Leon Nielsen,

7
Nel caso di SQL Azure, le due tabelle di destinazione sono sys.sql_logins e sys.sysusers - potrebbe essere utile includerlo nella risposta.
Brett,

Non utile se lo script deve utilizzare un nome utente variabile.
Ross Presser,

@Derek Morrison possiamo aggiungere un'altra condizione per SID
AstroBoy

30

Come aggiunta minore a questo thread, in generale si desidera evitare di utilizzare le viste che iniziano con sys.sys * poiché Microsoft le include solo per compatibilità con le versioni precedenti. Per il tuo codice, probabilmente dovresti usare sys.server_principals. Ciò presuppone che si stia utilizzando SQL 2005 o versioni successive.


Testato, funziona e più attuale delle altre risposte. +1 anche a te.
David

Sì, con il 2005 Microsoft ha rimosso l'accesso diretto alle tabelle di sistema. Per evitare di rompere il vecchio codice, includono viste con lo stesso nome delle vecchie tabelle. Tuttavia, sono pensati solo per il codice più vecchio e il codice più recente dovrebbe usare le nuove viste. In BOL, fai una ricerca sulle tabelle di sistema di mappatura per scoprire cosa dovresti usare.
Bomlin,

11

È possibile utilizzare la funzione integrata:

SUSER_ID ( [ 'myUsername' ] )

attraverso

IF [value] IS NULL [statement]

piace:

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


Eseguito l'upgrade per l'inclusione di campi opzionali disabilitando la politica e i controlli di scadenza.
Archibald,

8

Prova questo (sostituisci "utente" con il nome di accesso effettivo):

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

BEGIN 
    --create login here
END

@Marc: scusa ma ti sbagli. La tabella [syslogins] mantiene gli accessi e la tabella [sysusers] mantiene gli utenti.
abatishchev,

6

Funziona su SQL Server 2000.

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

su SQL 2005, modificare la seconda riga in

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

Non sono sicuro di SQL 2008, ma suppongo che sarà lo stesso di SQL 2005 e, in caso contrario, questo dovrebbe darti un'idea di dove iniziare a cercare.


5

cosa vuoi verificare esattamente per l'accesso o l'utente? un accesso viene creato a livello di server e un utente viene creato a livello di database, quindi un accesso è univoco nel server

anche un utente viene creato con un accesso, un utente senza accesso è un utente orfano e non è utile poiché non è possibile eseguire l'accesso al server sql senza un accesso

forse hai bisogno di questo

controlla il login

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

la query sopra restituisce 'X' se il login esiste altrimenti restituisce null

quindi crea un login

CREATE LOGIN <username> with PASSWORD=<password>

questo crea un login nel server sql. ma accetta solo password complesse

creare un utente in ogni database per il quale si desidera accedere come

CREATE USER <username> for login <username>

assegnare i diritti di esecuzione all'utente

 GRANT EXECUTE TO <username>

DEVI AVERE le autorizzazioni SYSADMIN o dire 'sa' in breve

puoi scrivere una procedura sql per quella su un database

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

Per gestire i conflitti di denominazione tra accessi, ruoli, utenti, ecc., È necessario controllare la typecolonna in base a documentazione Microsoft sys.database_principals

Per gestire capitoli speciali in nomi utente ecc., Utilizzare N'<name>'e[<name>] conseguenza.

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

Crea un utente del database

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

Crea ruolo database

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

Aggiungi utente al ruolo

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

Concedere i diritti al ruolo

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


-1

Per prima cosa devi controllare l'esistenza del login usando la vista syslogins:

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

Quindi devi controllare l'esistenza del tuo database:

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
Non so - dire che "devi controllare l'esistenza del login usando la vista syslogins", quindi pubblicare il codice che non usa quella vista sembra un problema di copia e incolla. Inoltre, dopo la prima istruzione, la riga "Quindi devi controllare l'esistenza del tuo database", usando un modulo parallelo, sembra che stai chiedendo a qualcuno di verificare l'esistenza di un database, non di un utente di livello DB. È necessario specificare che il secondo batch deve essere eseguito all'interno del DB di destinazione. Nel complesso, questa è solo una spiegazione molto scadente. E da quando l'hai aggiunta cinque anni dopo che la risposta più votata ha detto lo stesso, ma meglio ...
Ridere Vergil il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.