Memeriksa apakah login SQL Server sudah ada

176

Saya perlu memeriksa apakah login tertentu sudah ada di SQL Server, dan jika tidak, maka saya perlu menambahkannya.

Saya telah menemukan kode berikut untuk benar-benar menambahkan login ke database, tetapi saya ingin membungkus ini dalam pernyataan IF (entah bagaimana) untuk memeriksa apakah login tersebut ada terlebih dahulu.

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

Saya mengerti bahwa saya perlu menginterogasi database sistem, tetapi tidak yakin harus mulai dari mana!

Brett Rigby
sumber
10
Ini adalah pertanyaan penting, tetapi seperti yang diungkapkan, sepertinya ada perbedaan penting: pengguna vs. login. Duplikat potensial yang dikaitkan dengan Jon sepertinya adalah tentang pengguna. Pertanyaan ini mengatakan "pengguna" dalam judul, tetapi berkaitan dengan login dalam kode pertanyaan dan jawaban yang diterima. Saya mengedit judul dan pertanyaan sesuai.
LarsH
1
Hanya untuk menambahkan komentar oleh @ LarsH, login dikaitkan dengan contoh server SQL, dan pengguna dikaitkan dengan database tertentu. Pengguna basis data dapat dibuat dari login server, sehingga mereka memiliki akses ke database tertentu. Lihat artikel yang luar biasa ini dan bahkan seluruh rangkaiannya adalah bagian dari (Stariway to SQL Server Security)
Reversed Engineer

Jawaban:

141

Dari sini

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
sumber
6
Anda harus menggunakan QUOTENAME untuk mencegah injeksi sql. Penyerang dapat melewati @loginName sepertix] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu
2
Mengapa perlu membuat pernyataan sebagai string dan kemudian menggunakan sp_executesql, daripada hanya memasukkan secara langsung CREATE LOGIN [@loginName] FROM ...? Maafkan ketidaktahuan saya, saya ingin belajar ...
LarsH
4
@ LarsH: Membuat pernyataan sebagai string diperlukan karena CREATE LOGIN tidak dapat menggunakan parameter untuk nama login, itu membutuhkan string literal. Tidak yakin mengapa itu terjadi, tetapi saya menemukan bahwa itu memang benar.
Joseph Bongaarts
@ JosephephBongaarts: Oke, terima kasih. Saya kira itu seperti nama tabel dalam pernyataan SELECT. Mungkin idenya adalah untuk mengurangi luas permukaan yang rentan terhadap serangan, meskipun saya tidak tahu itu akan membantu.
LarsH
1
Saya pikir QUOTENAME()berkeliling @loginName, bukan seluruh pernyataan, dan kemudian Anda dapat menyingkirkan manual [dan] pembatas di sekitar @loginName.
brianary
288

Berikut adalah cara untuk melakukan ini di SQL Server 2005 dan yang lebih baru tanpa menggunakan tampilan syslogins yang sudah usang:

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

Tampilan server_principals digunakan alih-alih sql_logins karena yang terakhir tidak mencantumkan login Windows.

Jika Anda perlu memeriksa keberadaan pengguna dalam database tertentu sebelum membuatnya, maka Anda dapat melakukan ini:

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
sumber
17
Jawaban terbaik, tidak ada sql dinamis yang terlibat, atau penggunaan tampilan yang usang. Terima kasih!
Casper Leon Nielsen
7
Dalam kasus SQL Azure, dua tabel target adalah sys.sql_logins dan sys.sysusers - mungkin baik untuk memasukkan ini dalam jawaban.
Brett
Tidak berguna jika skrip Anda perlu menggunakan nama pengguna variabel.
Ross Presser
@Derek Morrison dapatkah kita menambahkan satu syarat lagi untuk SID
AstroBoy
30

Sebagai tambahan kecil untuk utas ini, secara umum Anda ingin menghindari menggunakan tampilan yang dimulai dengan sys.sys * karena Microsoft hanya menyertakannya untuk kompatibilitas mundur. Untuk kode Anda, Anda mungkin harus menggunakan sys.server_principals. Ini dengan asumsi Anda menggunakan SQL 2005 atau lebih besar.

Bomlin
sumber
Diuji, berfungsi, dan lebih terkini dari jawaban lainnya. Memberi +1 kepada Anda juga.
David
Ya, dengan 2005 Microsoft mengambil akses langsung ke tabel sistem. Agar tidak melanggar kode lama, mereka menyertakan tampilan yang memiliki nama yang sama dengan tabel lama. Namun, mereka hanya dimaksudkan untuk kode lama dan kode yang lebih baru harus menggunakan pandangan baru. Di BOL, lakukan pencarian pada Tabel Sistem Pemetaan untuk mencari tahu apa yang harus Anda gunakan.
Bomlin
11

Anda dapat menggunakan fungsi bawaan:

SUSER_ID ( [ 'myUsername' ] )

melalui

IF [value] IS NULL [statement]

Suka:

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

Huma
sumber
Terpilih untuk dimasukkannya bidang opsional yang menonaktifkan kebijakan dan pemeriksaan kedaluwarsa.
Archibald
8

Coba ini (ganti 'pengguna' dengan nama login yang sebenarnya):

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

BEGIN 
    --create login here
END
Marc
sumber
@ Markc: Maaf, tetapi Anda salah. Tabel [syslogins] menyimpan login dan tabel [sysusers] menjaga pengguna.
abatishchev
6

Ini berfungsi pada SQL Server 2000.

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

pada SQL 2005, ubah baris ke-2 menjadi

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

Saya tidak yakin tentang SQL 2008, tapi saya menduga itu akan sama dengan SQL 2005 dan jika tidak, ini akan memberi Anda gambaran tentang di mana mulai mencari.

David
sumber
5

apa yang sebenarnya ingin Anda periksa login atau pengguna? login dibuat di level server dan pengguna dibuat di level database sehingga login unik di server

juga pengguna dibuat terhadap login, pengguna tanpa login adalah pengguna yatim dan tidak berguna karena Anda tidak dapat melakukan login server sql tanpa login

mungkin kamu membutuhkan ini

periksa login

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

kueri di atas mengembalikan 'X' jika login ada lagi mengembalikan nol

lalu buat login

CREATE LOGIN <username> with PASSWORD=<password>

ini menciptakan login di sql server. tetapi hanya menerima kata sandi yang kuat

buat pengguna di setiap basis data yang Anda inginkan untuk login

CREATE USER <username> for login <username>

memberikan hak eksekusi kepada pengguna

 GRANT EXECUTE TO <username>

ANDA HARUS MEMILIKI izin SYSADMIN atau mengatakan 'sa' singkatnya

Anda dapat menulis prosedur sql untuk itu di 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
Akshita
sumber
5

Untuk menangani konflik penamaan antara login, peran, pengguna dll. Anda harus memeriksa typekolom sesuai dengan dokumentasi Microsoft sys.database_principals

Untuk menangani karakter khusus dalam nama pengguna dll, gunakan N'<name>'dan [<name>]sesuai.

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

Buat pengguna basis data

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

Buat peran basis data

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

Tambahkan pengguna ke peran

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

Berikan hak untuk peran

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
sumber
-1

Pertama, Anda harus memeriksa keberadaan login menggunakan tampilan syslogins:

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

Maka Anda harus memeriksa keberadaan basis data Anda:

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
sumber
1
Saya tidak tahu - mengatakan bahwa "Anda harus memeriksa keberadaan login menggunakan tampilan syslogins", kemudian memposting kode yang tidak menggunakan tampilan itu terlihat seperti masalah salin dan tempel. Juga, setelah pernyataan pertama, baris "Maka Anda harus memeriksa keberadaan basis data Anda", menggunakan bentuk paralel, sepertinya Anda meminta seseorang untuk memeriksa keberadaan basis data, bukan pengguna level DB. Dan Anda perlu menentukan bahwa batch kedua harus dijalankan di dalam target DB. Secara keseluruhan, ini hanya penjelasan yang sangat buruk. Dan karena Anda menambahkannya lima tahun setelah jawaban tertinggi yang dipilih mengatakan hal yang sama, tetapi lebih baik ...
Tertawa Vergil