Bir SQL Server girişinin zaten mevcut olup olmadığını kontrol etme


176

SQL Server'da belirli bir girişin zaten var olup olmadığını kontrol etmem gerekiyor ve yoksa, eklemem gerekiyor.

Ben aslında veritabanına giriş eklemek için aşağıdaki kodu bulduk, ama bu giriş ilk olup olmadığını kontrol etmek için bir şekilde (bir şekilde) bir IF deyiminde sarmak istiyorum.

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

Bir sistem veritabanını sorgulamamız gerektiğini anlıyorum, ancak nereden başlayacağınızdan emin değilim!


10
Bu önemli bir soru, ancak ifade edildiği gibi, önemli bir ayrımı kaçırıyor gibi görünüyor: kullanıcı ve giriş. Jon'un bağlantı kurduğu potansiyel kopya gerçekten kullanıcılar hakkında. Bu soru başlıkta "kullanıcı" diyor, ancak soru kodunda ve kabul edilen cevapta oturum açmayla ilgili. Başlığı ve soruyu buna göre düzenledim.
LarsH

1
Sadece @LarsH tarafından yoruma eklemek için girişler bir SQL sunucusu örneğiyle ilişkilendirilir ve kullanıcılar belirli bir veritabanıyla ilişkilendirilir. Veritabanı kullanıcıları sunucu oturumlarından oluşturulabilir, böylece belirli bir veritabanına erişebilirler. Bkz bu mükemmel makale ve aslında bütün dizisi bu (SQL Server Security Stariway) bir parçasıdır
Geriye döndürülmüş Mühendisi

Yanıtlar:


141

Gönderen burada

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
sql enjeksiyonunu önlemek için QUOTENAME kullanmalısınız. Attacker gibi bir @loginName geçebilirx] with password ''y'';\r\ndrop table foo;\r\n
Remus

2
Dize olarak bir ifade oluşturmak ve sonra doğrudan girmek yerine sp_executesql kullanmak neden gerekliydi CREATE LOGIN [@loginName] FROM ...? Cehaletimi
affedin

4
@LarsH: CREATE LOGIN giriş adı için bir parametre kullanamadığından, bir dize değişmezi gerektirdiğinden, ifadeyi dize olarak oluşturmak gerekir. Bunun neden olduğundan emin değilim, ama bunun doğru yolunu öğrendim.
Joseph Bongaarts

@JosephBongaarts: Tamam, teşekkürler. Sanırım SELECT ifadelerinde tablo isimleri gibi. Belki de fikir, saldırılara karşı savunmasız olan yüzey alanını azaltmaktır, ancak bunun yardımcı olacağını bilmiyorum.
LarsH

1
Bence tüm ifade değil, QUOTENAME()etrafta dolaşıyor @loginNameve sonra etraftaki manuel ve sınırlayıcılardan kurtulabilirsiniz @loginName.
brianary

288

Kullanımdan kaldırılmış syslogins görünümünü kullanmadan SQL Server 2005 ve sonraki sürümlerde bunu yapmanın bir yolu:

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

Sql_logins yerine server_principals görünümü kullanılır, çünkü ikincisi Windows oturumlarını listelemez.

Oluşturmadan önce belirli bir veritabanında bir kullanıcının varlığını kontrol etmeniz gerekiyorsa, bunu yapabilirsiniz:

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
En iyi yanıt, dinamik sql veya herhangi bir kullanımdan kaldırılmış görünüm kullanımı yok. Teşekkürler!
Casper Leon Nielsen

7
SQL Azure durumunda, iki hedef tablo sys.sql_logins ve sys.sysusers şeklindedir - bunu cevaba eklemek güzel olabilir.
Brett

Komut dosyanızın değişken bir kullanıcı adı kullanması gerekiyorsa yararlı değildir.
Ross Presser

@Derek Morrison biz SID için bir tane daha koşul ekleyebiliriz
Astroboy

30

Bu iş parçacığına küçük bir ek olarak, genel olarak sys.sys * ile başlayan görünümleri kullanmaktan kaçınmak istersiniz, çünkü Microsoft bunları yalnızca geriye dönük uyumluluk için içerir. Kodunuz için muhtemelen sys.server_principals kullanmalısınız. Bu, SQL 2005 veya üstünü kullandığınızı varsayar.


Test edildi, çalışıyor ve diğer yanıtlardan daha güncel. Size de + 1'leyin.
David

Evet, 2005 ile Microsoft sistem tablolarına doğrudan erişimi kaldırdı. Eski kodu kırmamak için, eski tablolarla aynı ada sahip görünümler içerirler. Ancak, yalnızca eski kod içindir ve yeni kod yeni görünümleri kullanmalıdır. BOL'de, ne kullanmanız gerektiğini öğrenmek için Eşleme Sistemi Tabloları'nda bir arama yapın.
Bomlin

11

Yerleşik işlevi kullanabilirsiniz:

SUSER_ID ( [ 'myUsername' ] )

üzerinden

IF [value] IS NULL [statement]

sevmek:

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


Politika ve sona erme kontrollerini devre dışı bırakan isteğe bağlı alanların dahil edilmesi için oy verildi.
Archibald

8

Bunu deneyin ('kullanıcı'yı gerçek giriş adıyla değiştirin):

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

BEGIN 
    --create login here
END

@Marc: Üzgünüm ama yanılıyorsun. Tablo [syslogins] girişleri tutarken, tablo [sysusers] kullanıcıları tutar.
abatishchev

6

Bu SQL Server 2000'de çalışır.

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

SQL 2005'te 2. satırı değiştirin

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

SQL 2008'den emin değilim, ancak SQL 2005 ile aynı olacağını tahmin ediyorum ve eğer değilse, bu size nereden bakmaya başladığı hakkında bir fikir vermelidir.


5

giriş veya kullanıcı için tam olarak ne kontrol etmek istiyorsun? sunucu düzeyinde bir giriş oluşturulur ve veritabanı düzeyinde bir kullanıcı oluşturulur, böylece bir giriş sunucuda benzersizdir

Ayrıca bir kullanıcı bir giriş karşı oluşturulur, giriş olmadan bir kullanıcı yetim bir kullanıcı ve u bir giriş olmadan sql sunucusu giriş yapamaz gibi yararlı değildir

belki buna ihtiyacın var

giriş için kontrol et

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

eğer giriş mevcutsa yukarıdaki sorgu dönüşü 'X' başka döndürür null

sonra bir giriş oluşturun

CREATE LOGIN <username> with PASSWORD=<password>

Bu sql sunucusunda bir oturum açma oluşturur. ama sadece güçlü şifreleri kabul eder

giriş yapmak istediğiniz her veritabanında bir kullanıcı oluşturun

CREATE USER <username> for login <username>

kullanıcıya yürütme hakları atama

 GRANT EXECUTE TO <username>

SYSADMIN izinlerine sahip olmanız veya kısaca 'sa' demeniz gerekir

bir veritabanına bunun için bir sql yordamı yazabilirsiniz

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

Oturum açma bilgileri, roller, kullanıcılar vb. Arasındaki adlandırma çakışmasını önlemek için typesütunu Microsoft sys.database_principals belgelerine göre kontrol etmelisiniz.

Kullanıcı adlarında vb. Özel bölümleri ele almak için N'<name>'ve [<name>]buna göre kullanın .

Giriş oluştur

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>

Veritabanı kullanıcısı oluştur

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

Veritabanı rolü oluştur

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

Role kullanıcı ekle

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

Role hak verme

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


-1

Öncelikle syslogins görünümünü kullanarak giriş varlığını kontrol etmelisiniz:

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

Sonra veritabanı varlığını kontrol etmek zorunda:

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
Ben "syslogins görünümünü kullanarak giriş varlığını kontrol etmek zorunda" diyen, sonra bu görünümü kullanmayan kod gönderme bir kopyala yapıştır gibi görünüyor diyorum. Ayrıca, ilk ifadeden sonra, paralel form kullanarak "O zaman veritabanı varlığınızı kontrol etmek zorundasınız" satırı, birisinden DB düzeyinde bir kullanıcı değil, bir veritabanının varlığını kontrol etmesini istiyormuşsunuz gibi görünüyor. İkinci partinin hedef DB içinde çalıştırılması gerektiğini belirtmeniz gerekir. Genel olarak, bu sadece çok kötü bir açıklama. Ve en yüksek oylanan cevabın aynı şeyi söyledikten beş yıl sonra eklediğinizden beri ...
Gülüyor Vergil
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.