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 2013年

1
@LarsHによるコメントに追加するだけで、ログインはSQLサーバーインスタンスに関連付けられ、ユーザーは特定のデータベースに関連付けられます。データベースユーザーはサーバーログインから作成できるため、特定のデータベースにアクセスできます。参照してください。この優れた記事を、実際にシリーズ全体では、それは(SQL ServerのセキュリティへのStariway)の一部である
逆にエンジニア

回答:


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
SQLインジェクションを防ぐには、QUOTENAMEを使用する必要があります。攻撃者は@loginNameを渡すことができますx] with password ''y'';\r\ndrop table foo;\r\n
Remus Rusanu

2
ステートメントを文字列として作成し、直接入力するだけでなく、sp_executesqlを使用する必要があったのはなぜCREATE LOGIN [@loginName] FROM ...ですか。私の無知を
許してください

4
@LarsH:CREATE LOGINはログイン名のパラメーターを使用できないため、文字列としてステートメントを作成する必要があります。文字列リテラルが必要です。それがなぜかはわかりませんが、私はそれが本当であるという難しい方法を見つけました。
ジョセフBongaarts 14

@JosephBongaarts:OK、ありがとう。SELECTステートメントのテーブル名のようなものだと思います。おそらく、攻撃に対して脆弱な表面領域を減らすことですが、それが役立つかどうかはわかりません。
LarsH 2014

1
ステートメント全体ではなく、QUOTENAME()周りを回ると思います。そう@loginNameすれば、手動の[および]区切り文字を取り除くことができます@loginName
ブライアリー2015

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

後者はWindowsログインをリストしないため、sql_loginsの代わりにserver_principalsビューが使用されます。

ユーザーを作成する前に特定のデータベースにユーザーが存在するかどうかを確認する必要がある場合は、次のようにします。

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は含まれず、非推奨のビューの使用法もありません。ありがとう!
キャスパーレオンニールセン

7
SQL Azureの場合、2つのターゲットテーブルはsys.sql_loginsとsys.sysusersです。これを回答に含めるとよいでしょう。
ブレット

スクリプトが変数のユーザー名を使用する必要がある場合は役に立ちません。
ロスプレッサー

@Derek Morrisonは、SIDにもう1つの条件を追加できますか
AstroBoy

30

このスレッドへのマイナーな追加として、Microsoftは後方互換性のためだけにビューを含めているため、一般的にはsys.sys *で始まるビューの使用を避けたいと思います。コードでは、おそらくsys.server_principalsを使用する必要があります。これは、SQL 2005以降を使用していることを前提としています。


テストされ、機能し、他の回答よりも最新です。あなたにも+1します。
デビッド

ええ、2005年にマイクロソフトはシステムテーブルへの直接アクセスを廃止しました。古いコードを壊さないようにするために、古いテーブルと同じ名前のビューが含まれています。ただし、これらは古いコードのみを対象としており、新しいコードでは新しいビューを使用する必要があります。BOLで、マッピングシステムテーブルを検索して、何を使用する必要があるかを確認します。
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

これを試してください(「user」を実際のログイン名に置き換えます):

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

BEGIN 
    --create login here
END

@マーク:申し訳ありませんが、あなたは間違っています。テーブル[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のドキュメントます

ユーザー名などの特殊文字を処理するには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ビューを使用してログインの存在を確認する必要がある」と言ってから、そのビューを使用しないコードを投稿すると、コピーアンドペーストの問題のように見えます。また、最初のステートメントの後の「データベースの存在を確認する必要があります」という行は、並列形式を使用して、DBレベルのユーザーではなく、データベースの存在を確認するように依頼しているように見えます。また、2番目のバッチをターゲットDB内で実行する必要があることを指定する必要があります。全体として、これは非常に悪い説明です。そして、最高の投票された回答が同じであると言ってから5年後にそれを追加したので、より良い...
Vergil
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.