ログオントリガーは、その名前が示すように、SQLServerのLOGONイベントに応答して起動するトリガーです。
簡単に言うと、誰かがデータベースサーバーへの新しい接続を確立しようとすると、ログオントリガーが起動します。トリガーは、ユーザー認証とログインフェーズが完了した後、ユーザーセッションが実際に開始される前に起動します。
ログオントリガーの利点
ログオントリガーにはいくつかの利点があります。
- ログインアクティビティの追跡
ログオントリガーを使用して、データベースサーバーで行われているログインアクティビティを追跡できます。たとえば、指定した期間内にデータベースサーバーにログインしたすべてのユーザーのリストを維持するために使用できます。 - 接続総数の制限
データベースログインが多すぎると、特に多数のユーザーがデータベースにアクセスしている場合に、データベースのパフォーマンスに影響を与える可能性があります。このような場合、ログオントリガーを使用して、さらに許可される前に、すでに存在するログインの総数をチェックできます。 - 接続ごとのセッション数の制限
ログオントリガーを使用して、接続ごとのセッション数を制限できます。ユーザーが新しいセッションを確立しようとするたびに、ログオントリガーは、そのログインですでにアクティブになっているセッションの数を確認し、制限を超えた場合は新しいセッションを制限できます。
始める前に、完全にバックアップされていることを確認してください。
アクティブなユーザー接続へのアクセス
次のスクリプトは、すべてのアクティブなユーザー接続をデータベースに返します。
SELECT * FROM sys.dm_exec_sessions
sys.dm_exec_sessionsは、すべてのアクティブなユーザー接続を返すシステムビューです。上記のクエリの出力は次のようになります:
出力には、アクティブなすべての接続に関する詳細情報が含まれます。 is_user_processとoriginal_login_nameの2つの列に関心があります。
前者は接続がユーザープロセスによって行われたかどうかを示し、前者はログインを行った接続の名前に関する情報を含みます。
次のクエリを実行します:
SELECT is_user_process, original_login_name, * FROM sys.dm_exec_sessions ORDER BY login_time DESC
上記のクエリは、sys.dm_exec_sessionsビューの残りのすべての列とともに、最初と2番目の列としてis_user_processとoriginal_login_nameを返します。ログイン時間の降順で結果をソートします。したがって、最近のほとんどの接続が一番上に表示されます。
出力で、is_user_process列に1が含まれている行まで下にスクロールします。
私の場合、以下の出力に示すような2つの行があります。
original_login_name列には、ログインを行った接続の名前(この場合は私のPCの名前)が表示されます。 program_name列で、接続のタイプを確認できます。上記の場合、session_id 51との接続は、SQLServerオブジェクトエクスプローラーとの接続です。 session_id 52との接続は、スクリプトが実行されている唯一のクエリウィンドウへの接続です。 2つのクエリウィンドウを開いている場合は、ここに合計3つのユーザー接続が表示されます。
ユーザープロセスによって確立された接続の総数をカウントするには、次のクエリを実行します。
SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1
サーバーにuser_process接続が2つしかないため、上記のクエリは2つを返します。
ログイン数を制限するためのログオントリガー
1つの接続で実行できるログインの総数を3に制限する単純なログオントリガーを作成しましょう。接続が4回目にデータベースサーバーにログインしようとすると、ログオントリガーはログインプロセスをロールバックします。
このトリガーのスクリプトは次のとおりです。
CREATE TRIGGER tr_CheckLogin ON ALL SERVER FOR LOGON AS BEGIN DECLARE @login NVARCHAR(100) SET @login = ORIGINAL_LOGIN() IF (SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1 AND original_login_name = @login) > 3 BEGIN Print 'More than three connections not allowed - Connection by ' + @login + ' Failed' ROLLBACK END END
上記のスクリプトでは、tr_CheckLoginという名前のトリガーを作成します。トリガースコープはサーバーに設定されています。
次の図に示すように、[オブジェクトエクスプローラー]->[サーバーオブジェクト]->[トリガー]に移動すると、トリガーの詳細を表示できます。
LOGONイベントが発生するたびに、つまり接続がサーバーにログインしようとするたびに、トリガーが起動します。トリガーの本体を注意深く見てください。
ORIGINAL_LOGIN関数は、サーバーにログインしようとしているユーザープロセスまたは接続の名前を返します。次に、sys.dm_exec_sessionビューを使用して、同じ名前の接続の総数がカウントされます。接続数が3を超える場合、ログインはロールバックされ、「3つを超える接続は許可されていません–「connection_name」による接続に失敗しました」というステートメントがユーザーに出力されます。
これを確認するには、SQLServer管理スタジオで新しいクエリウィンドウを開きます
注:以前は、2つの接続が開いていました。1つはSQL Server Management Studio用で、もう1つはクエリウィンドウ用です。
新しいクエリウィンドウを開こうとすると、tr_CheckLoginトリガーが起動しますが、この時点でログインの総数は3になるため、トリガーはログインをロールバックしません。
user_processによる接続の総数を確認するには、次のクエリを実行します。
SELECT COUNT(*) FROM sys.dm_exec_sessions WHERE is_user_process = 1
これで、出力に示されているように、合計3つのユーザー接続があります。
ここで、SQL Server Management Studioで新しいクエリウィンドウを開いて、新しい接続を作成してみてください。
次のエラーが表示されます:
エラーは、トリガーの実行が原因で「DESKTOP-GLQ5VRA \ Mani」(私のPCの名前)のログインに失敗したことを示しています。基本的に、作成したトリガーは接続を許可しませんでした。待って!しかし、私たちが印刷したエラーメッセージはどこにありますか?上記のメッセージボックスには表示されません。トリガーに書き込んだカスタムエラーメッセージは、エラーログで確認できます。
エラーログを表示するには、次のスクリプトを実行します。
EXECUTE sp_readerrorlog
ログオントリガー用に作成したカスタムメッセージが見つかるまで、エラーログを下にスクロールします。次のスクリーンショットは、データベースサーバーのエラーログを示しています。カスタムメッセージはエラーログに表示されます:
参考資料:
- YouTube:SQLServerログオントリガー
- Microsoft.com:ログオントリガー
- SQL調査:暴走したログオントリガーからの脱出