Kiểm tra xem đã đăng nhập SQL Server chưa


176

Tôi cần kiểm tra xem một thông tin đăng nhập cụ thể đã tồn tại trên SQL Server chưa và nếu không, thì tôi cần phải thêm nó.

Tôi đã tìm thấy đoạn mã sau để thực sự thêm thông tin đăng nhập vào cơ sở dữ liệu, nhưng tôi muốn bọc mã này trong câu lệnh IF (bằng cách nào đó) để kiểm tra xem đăng nhập có tồn tại trước không.

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

Tôi hiểu rằng tôi cần phải thẩm vấn một cơ sở dữ liệu hệ thống, nhưng không chắc bắt đầu từ đâu!


10
Đây là một câu hỏi quan trọng, nhưng như phrased, nó dường như bỏ lỡ một sự phân biệt quan trọng: người dùng so với đăng nhập. Bản sao tiềm năng mà Jon liên kết đến thực sự dường như là về người dùng. Câu hỏi này cho biết "người dùng" trong tiêu đề, nhưng xử lý thông tin đăng nhập trong mã câu hỏi và trong câu trả lời được chấp nhận. Tôi chỉnh sửa tiêu đề và câu hỏi cho phù hợp.
LarsH

1
Chỉ cần thêm vào nhận xét của @LarsH, thông tin đăng nhập được liên kết với một phiên bản máy chủ SQL và người dùng được liên kết với một cơ sở dữ liệu cụ thể. Người dùng cơ sở dữ liệu có thể được tạo từ thông tin đăng nhập máy chủ, vì vậy họ có quyền truy cập vào cơ sở dữ liệu cụ thể. Xem bài viết xuất sắc này và trên thực tế, toàn bộ loạt bài này là một phần của (Stariway to SQL Server Security)
Kỹ sư đảo ngược

Câu trả lời:


141

Từ đây

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
bạn nên sử dụng QUOTENAME để ngăn ngừa tiêm sql. Kẻ tấn công có thể vượt qua @loginName nhưx] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu

2
Tại sao cần phải tạo một câu lệnh dưới dạng chuỗi và sau đó sử dụng sp_executesql, thay vì chỉ nhập trực tiếp CREATE LOGIN [@loginName] FROM ...? Xin tha thứ cho sự thiếu hiểu biết của tôi, tôi muốn tìm hiểu ...
LarsH

4
@LarsH: Tạo câu lệnh dưới dạng chuỗi là bắt buộc vì CREATE LOGIN không thể sử dụng tham số cho tên đăng nhập, nó yêu cầu một chuỗi bằng chữ. Không chắc tại sao, nhưng tôi phát hiện ra một cách khó khăn là sự thật.
Joseph Bongaarts

@JosephBongaarts: OK, cảm ơn. Tôi đoán nó giống như tên bảng trong các câu lệnh CHỌN. Có lẽ ý tưởng là giảm diện tích bề mặt dễ bị tấn công, mặc dù tôi không biết rằng nó sẽ giúp ích.
LarsH

1
Tôi nghĩ rằng QUOTENAME()đi xung quanh @loginName, không phải toàn bộ tuyên bố, và sau đó bạn có thể thoát khỏi các dấu phân cách [và] thủ công xung quanh @loginName.
brianary

288

Đây là một cách để làm điều này trong SQL Server 2005 trở lên mà không cần sử dụng khung nhìn syslogins không dùng nữa:

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

Khung nhìn server_principals được sử dụng thay vì sql_logins vì cái sau không liệt kê thông tin đăng nhập Windows.

Nếu bạn cần kiểm tra sự tồn tại của người dùng trong cơ sở dữ liệu cụ thể trước khi tạo chúng, thì bạn có thể làm điều này:

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
Câu trả lời tốt nhất, không có sql động liên quan, cũng không sử dụng chế độ xem không dùng nữa. Cảm ơn!
Casper Leon Nielsen

7
Trong trường hợp của SQL Azure, hai bảng đích là sys.sql_logins và sys.sysusers - có thể rất hay để đưa điều này vào câu trả lời.
Brett

Không hữu ích nếu tập lệnh của bạn cần sử dụng tên người dùng thay đổi.
Ross Presser

@Derek Morrison chúng ta có thể thêm một điều kiện nữa cho SID
AstroBoy

30

Là một bổ sung nhỏ cho chủ đề này, nói chung, bạn muốn tránh sử dụng các chế độ xem bắt đầu bằng sys.sys * vì Microsoft chỉ bao gồm chúng để tương thích ngược. Đối với mã của bạn, có lẽ bạn nên sử dụng sys.server_principals. Điều này giả sử bạn đang sử dụng SQL 2005 trở lên.


Đã thử nghiệm, hoạt động, và hiện tại hơn các câu trả lời khác. +1 cho bạn là tốt.
David

Vâng, với năm 2005 Microsoft đã lấy đi quyền truy cập trực tiếp vào các bảng hệ thống. Để tránh phá vỡ mã cũ, chúng bao gồm các khung nhìn có cùng tên với các bảng cũ. Tuy nhiên, chúng chỉ dành cho mã cũ và mã mới hơn nên sử dụng các khung nhìn mới. Trong BOL, thực hiện tìm kiếm trên Bảng hệ thống bản đồ để tìm hiểu những gì bạn nên sử dụng.
Bomlin

11

Bạn có thể sử dụng chức năng tích hợp:

SUSER_ID ( [ 'myUsername' ] )

thông qua

IF [value] IS NULL [statement]

giống:

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/l Library / ms176042 (v = sql.110) .aspx


Nâng cấp để bao gồm các trường tùy chọn vô hiệu hóa chính sách và kiểm tra hết hạn.
Archibald

8

Hãy thử điều này (thay thế 'người dùng' bằng tên đăng nhập thực tế):

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

BEGIN 
    --create login here
END

@Marc: Xin lỗi nhưng bạn đã nhầm. Bảng [syslogins] giữ thông tin đăng nhập và bảng [sysusers] giữ người dùng.
abatishchev

6

Điều này hoạt động trên SQL Server 2000.

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

trên SQL 2005, thay đổi dòng thứ 2 thành

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

Tôi không chắc chắn về SQL 2008, nhưng tôi đoán rằng nó sẽ giống với SQL 2005 và nếu không, điều này sẽ cho bạn ý tưởng về nơi bắt đầu tìm kiếm.


5

Chính xác bạn muốn kiểm tra đăng nhập hoặc người dùng là gì? đăng nhập được tạo ở cấp máy chủ và người dùng được tạo ở cấp cơ sở dữ liệu để đăng nhập là duy nhất trong máy chủ

người dùng cũng được tạo ra để đăng nhập, người dùng không đăng nhập là người dùng mồ côi và không hữu ích vì bạn không thể thực hiện đăng nhập máy chủ sql mà không cần đăng nhập

có lẽ bạn cần cái này

kiểm tra đăng nhập

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

truy vấn trên trả về 'X' nếu đăng nhập tồn tại khác trả về null

sau đó tạo một đăng nhập

CREATE LOGIN <username> with PASSWORD=<password>

điều này tạo ra một đăng nhập trong máy chủ sql. Nhưng nó chỉ chấp nhận mật khẩu mạnh

tạo người dùng trong mỗi cơ sở dữ liệu bạn muốn đăng nhập như

CREATE USER <username> for login <username>

gán quyền thực thi cho người dùng

 GRANT EXECUTE TO <username>

BẠN PHẢI CÓ quyền SYSADMIN hoặc nói ngắn gọn là 'sa'

bạn có thể viết một thủ tục sql cho điều đó trên cơ sở dữ liệu

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

Để xử lý xung đột đặt tên giữa các lần đăng nhập, vai trò, người dùng, v.v., bạn nên kiểm tra typecột theo tài liệu của Microsoft sys.database_principals

Để xử lý các ký tự đặc biệt trong tên người dùng, v.v., hãy sử dụng N'<name>'[<name>]theo đó.

Tạo đăng nhập

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>

Tạo người dùng cơ sở dữ liệu

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

Tạo vai trò cơ sở dữ liệu

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

Thêm người dùng vào vai trò

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

Cấp quyền cho vai trò

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


-1

Trước tiên, bạn phải kiểm tra sự tồn tại của đăng nhập bằng cách sử dụng chế độ xem syslogins:

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

Sau đó, bạn phải kiểm tra sự tồn tại của cơ sở dữ liệu của bạn:

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
Tôi không biết - nói rằng "bạn phải kiểm tra sự tồn tại của đăng nhập bằng cách sử dụng chế độ xem syslogins", sau đó đăng mã không sử dụng chế độ xem đó trông giống như một vấn đề sao chép và dán. Ngoài ra, sau câu lệnh đầu tiên, dòng "Sau đó, bạn phải kiểm tra sự tồn tại của cơ sở dữ liệu của mình", sử dụng dạng song song, có vẻ như bạn đang yêu cầu ai đó kiểm tra sự tồn tại của cơ sở dữ liệu, chứ không phải người dùng ở mức DB. Và bạn cần xác định rằng lô thứ hai cần được chạy bên trong DB đích. Nhìn chung, đây chỉ là một lời giải thích rất kém. Và vì bạn đã thêm nó năm năm sau khi câu trả lời được đánh giá cao nhất cũng nói như vậy, nhưng tốt hơn ...
Vergil cười
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.