ตรวจสอบว่าการเข้าสู่ระบบ SQL Server มีอยู่แล้ว


176

ฉันต้องตรวจสอบว่าการเข้าสู่ระบบเฉพาะมีอยู่แล้วบน SQL Server และถ้ามันไม่ได้ฉันต้องเพิ่มมัน

ฉันพบรหัสต่อไปนี้เพื่อเพิ่มการเข้าสู่ระบบฐานข้อมูลจริง ๆ แต่ฉันต้องการที่จะใส่คำสั่ง IF (อย่างใด) เพื่อตรวจสอบว่าการเข้าสู่ระบบนั้นมีอยู่ก่อนหรือไม่

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

ฉันเข้าใจว่าฉันต้องสอบถามฐานข้อมูลระบบ แต่ไม่แน่ใจว่าจะเริ่มจากตรงไหน!


10
นี่เป็นคำถามสำคัญ แต่ตามวลีแล้วดูเหมือนว่าจะมีความแตกต่างที่สำคัญ: ผู้ใช้กับการเข้าสู่ระบบ ความซ้ำซ้อนที่จอนเชื่อมโยงกับน่าจะเกี่ยวกับผู้ใช้ คำถามนี้ระบุว่า "ผู้ใช้" ในชื่อเรื่อง แต่เกี่ยวข้องกับการเข้าสู่ระบบในรหัสคำถามและในคำตอบที่ยอมรับได้ ฉันแก้ไขชื่อและคำถามตามนั้น
LarsH

1
เพียงเพื่อเพิ่มความคิดเห็นโดย @LarsH การเข้าสู่ระบบจะเชื่อมโยงกับอินสแตนซ์ของเซิร์ฟเวอร์ SQL และผู้ใช้จะเชื่อมโยงกับฐานข้อมูลเฉพาะ ผู้ใช้ฐานข้อมูลสามารถสร้างได้จากการเข้าสู่ระบบเซิร์ฟเวอร์ดังนั้นพวกเขาจึงสามารถเข้าถึงฐานข้อมูลเฉพาะได้ ดูบทความที่ยอดเยี่ยมนี้และในความเป็นจริงทั้งชุดมันเป็นส่วนหนึ่งของ (Stariway to SQL Server Security)
วิศวกรที่กลับรายการ

คำตอบ:


141

จากที่นี่

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
คุณควรใช้ QUOTENAME เพื่อป้องกันการฉีด sql ผู้โจมตีสามารถส่งผ่าน @loginName ได้x] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu

2
ทำไมมันจำเป็นที่จะต้องสร้างคำสั่งเป็นสตริงแล้วใช้ sp_executesql มากกว่าแค่โดยตรงเข้ามาCREATE LOGIN [@loginName] FROM ...? ให้อภัยความไม่รู้ของฉันฉันต้องการที่จะเรียนรู้ ...
LarsH

4
@LarsH: การสร้างคำสั่งเป็นสตริงจำเป็นเนื่องจาก CREATE LOGIN ไม่สามารถใช้พารามิเตอร์สำหรับชื่อเข้าสู่ระบบได้นั้นจะต้องใช้ตัวอักษรสตริง ไม่แน่ใจว่าทำไมถึงเป็นเช่นนั้น แต่ฉันพบวิธีที่ยากจริง
Joseph Bongaarts

@JosephBongaarts: ตกลงขอบคุณ ฉันเดาว่ามันเหมือนกับชื่อตารางในคำสั่ง SELECT บางทีความคิดก็คือลดพื้นที่ผิวที่ไวต่อการถูกโจมตีถึงแม้ว่าฉันไม่รู้ว่ามันจะช่วยได้
LarsH

1
ฉันคิดว่าQUOTENAME()จะไปรอบ ๆ@loginNameไม่ใช่คำสั่งทั้งหมดแล้วคุณสามารถกำจัด [และ] ตัวคั่นรอบ ๆ@loginNameได้
ไบรอัน

288

นี่คือวิธีการทำเช่นนี้ใน SQL Server 2005 และใหม่กว่าโดยไม่ใช้มุมมอง syslogins ที่เลิกใช้แล้ว:

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

มุมมอง server_principals ถูกนำมาใช้แทน sql_logins เพราะหลังไม่ได้แสดงรายการการเข้าสู่ระบบ Windows

หากคุณต้องการตรวจสอบการมีอยู่ของผู้ใช้ในฐานข้อมูลเฉพาะก่อนที่จะสร้างพวกเขาคุณสามารถทำได้:

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
คำตอบที่ดีที่สุดไม่มีส่วนเกี่ยวข้องกับ sql ไดนามิกหรือการใช้มุมมองที่ไม่สนับสนุน ขอบคุณ!
Casper Leon Nielsen

7
ในกรณีของ SQL Azure ตารางเป้าหมายสองรายการคือ sys.sql_logins และ sys.sysusers - อาจดีถ้ารวมไว้ในคำตอบ
Brett

ไม่มีประโยชน์หากสคริปต์ของคุณต้องใช้ชื่อผู้ใช้ที่เปลี่ยนแปลงได้
Ross Presser

@Derek Morrison เราสามารถเพิ่มเงื่อนไขอีกหนึ่งเงื่อนไขสำหรับ SID
AstroBoy

30

ในฐานะที่เป็นส่วนเสริมเล็กน้อยของเธรดนี้โดยทั่วไปคุณต้องการหลีกเลี่ยงการใช้มุมมองที่ขึ้นต้นด้วย sys.sys * เนื่องจาก Microsoft เป็นเพียงการรวมไว้สำหรับการเข้ากันได้ย้อนหลัง สำหรับรหัสของคุณคุณควรใช้ sys.server_principals นี่คือสมมุติว่าคุณกำลังใช้ SQL 2005 ขึ้นไป


ผ่านการทดสอบทำงานและเป็นปัจจุบันมากกว่าคำตอบอื่น ๆ +1 ให้คุณเช่นกัน
David

ใช่ด้วย 2005 Microsoft เอาการเข้าถึงโดยตรงไปยังตารางระบบ เพื่อป้องกันการแตกหักรหัสเก่าพวกเขามีมุมมองที่มีชื่อเดียวกับตารางเก่า อย่างไรก็ตามมีไว้สำหรับรหัสที่เก่ากว่าและรหัสที่ใหม่กว่าเท่านั้นควรใช้มุมมองใหม่ ใน BOL ทำการค้นหาบน Mapping System Tables เพื่อค้นหาสิ่งที่คุณควรใช้
Bomlin

11

คุณสามารถใช้ฟังก์ชั่นในตัว:

SUSER_ID ( [ 'myUsername' ] )

ผ่านทาง

IF [value] IS NULL [statement]

ชอบ:

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


เพิ่มขึ้นเพื่อรวมฟิลด์ตัวเลือกปิดใช้งานการตรวจสอบนโยบายและการหมดอายุ
Archibald

8

ลองนี้ (แทนที่ 'ผู้ใช้' ด้วยชื่อเข้าสู่ระบบจริง):

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

BEGIN 
    --create login here
END

@Marc: ขออภัย แต่คุณผิด ตาราง [syslogins] เก็บการเข้าสู่ระบบและตาราง [sysusers] รักษาผู้ใช้
abatishchev

6

สิ่งนี้ใช้ได้กับ SQL Server 2000

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

บน SQL 2005 เปลี่ยนบรรทัดที่ 2 เป็น

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

ฉันไม่แน่ใจเกี่ยวกับ SQL 2008 แต่ฉันเดาว่ามันจะเหมือนกับ SQL 2005 และถ้าไม่เช่นนี้ควรบอกให้คุณทราบว่าจะเริ่มมองหาที่ใด


5

สิ่งที่คุณต้องการตรวจสอบว่าเข้าสู่ระบบหรือผู้ใช้? การเข้าสู่ระบบถูกสร้างขึ้นในระดับเซิร์ฟเวอร์และผู้ใช้ถูกสร้างขึ้นที่ระดับฐานข้อมูลดังนั้นการเข้าสู่ระบบจะไม่ซ้ำกันในเซิร์ฟเวอร์

ผู้ใช้ที่ถูกสร้างขึ้นต่อต้านการเข้าสู่ระบบผู้ใช้ที่ไม่มีการเข้าสู่ระบบเป็นผู้ใช้กำพร้าและไม่เป็นประโยชน์เนื่องจากคุณไม่สามารถเข้าสู่ระบบเซิร์ฟเวอร์ sql โดยไม่ต้องเข้าสู่ระบบ

บางทีคุณต้องการสิ่งนี้

ตรวจสอบการเข้าสู่ระบบ

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

ข้อความค้นหาข้างต้นจะส่งคืน 'X' หากการเข้าสู่ระบบนั้นมีอยู่จะส่งกลับค่า null

จากนั้นสร้างการเข้าสู่ระบบ

CREATE LOGIN <username> with PASSWORD=<password>

สิ่งนี้สร้างการเข้าสู่ระบบในเซิร์ฟเวอร์ sql แต่จะยอมรับรหัสผ่านที่คาดเดายากเท่านั้น

สร้างผู้ใช้ในแต่ละฐานข้อมูลที่คุณต้องการลงชื่อเข้าใช้

CREATE USER <username> for login <username>

กำหนดสิทธิ์ดำเนินการให้กับผู้ใช้

 GRANT EXECUTE TO <username>

คุณต้องมีสิทธิ์ SYSADMIN หรือพูดสั้น ๆ ว่า "sa"

คุณสามารถเขียนขั้นตอน sql สำหรับที่บนฐานข้อมูล

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

เพื่อจัดการการตั้งชื่อความขัดแย้งระหว่างการเข้าสู่ระบบบทบาทผู้ใช้ ฯลฯ คุณควรตรวจสอบtypeคอลัมน์ตามเอกสารของ Microsoft sys.database_principals

เพื่อที่จะจัดการกับ chacters พิเศษในชื่อผู้ใช้ ฯลฯ ให้ใช้N'<name>'และ[<name>]ตาม

สร้างการเข้าสู่ระบบ

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>

สร้างผู้ใช้ฐานข้อมูล

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

สร้างบทบาทฐานข้อมูล

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

เพิ่มผู้ใช้ในบทบาท

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

ให้สิทธิ์ในบทบาท

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


-1

ก่อนอื่นคุณต้องตรวจสอบการมีอยู่ของล็อกอินโดยใช้มุมมอง syslogins:

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

จากนั้นคุณต้องตรวจสอบฐานข้อมูลที่มีอยู่:

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
ฉันไม่รู้ - บอกว่า "คุณต้องตรวจสอบสถานะการเข้าสู่ระบบโดยใช้มุมมอง syslogins" จากนั้นโพสต์โค้ดที่ไม่ได้ใช้มุมมองนั้นดูเหมือนปัญหาการคัดลอกและวาง นอกจากนี้หลังจากคำสั่งแรกบรรทัด "จากนั้นคุณต้องตรวจสอบการมีอยู่ของฐานข้อมูลของคุณ" โดยใช้รูปแบบขนานดูเหมือนว่าคุณกำลังขอให้ใครบางคนตรวจสอบการมีอยู่ของฐานข้อมูลไม่ใช่ผู้ใช้ระดับฐานข้อมูล และคุณต้องระบุว่าชุดที่สองจะต้องทำงานภายในฐานข้อมูลเป้าหมาย โดยรวมแล้วนี่เป็นเพียงคำอธิบายที่แย่มาก และเนื่องจากคุณเพิ่มห้าปีหลังจากคำตอบ upvoted สูงสุดกล่าวว่าเหมือนกัน แต่ดีกว่า ...
หัวเราะเวอร์จิล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.