回答:
SQL Serverセキュリティモデルでは、基になるテーブルへのアクセスを許可せずに、ビューへのアクセスを許可できます。
コード例は概念を示すための優れた方法であるため、LoginDetails
テーブルとそれに対応するビューを使用して、以下を検討してください。
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE VIEW dbo.LoginDetailsView
AS
SELECT ld.Username
, ld.EmailAddress
, ld.LastLoggedInAt
FROM dbo.LoginDetails ld
WHERE ld.LastLoggedInAt IS NOT NULL;
GO
ログインとユーザーを作成し、そのユーザーに、テーブル自体を表示する権限を持たずに、ビューから行を選択する権限を割り当てます。
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
次に、2つのテスト行を挿入します。
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
これはセキュリティモデルをテストします。SELECT
ビューから選択しているため、最初のステートメントは成功しSELECT
ますが、ユーザーがテーブルに直接アクセスできないため、2番目のステートメントは失敗します。
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗ ║ユーザー名║メールアドレス║LastLoggedInAt║ ╠══════════╬══════════════╬═══════════════════════ ══╣ ║ユーザーy║y@y.com║2018-02-15 07:36:54.490║ ╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;
REVERT
質問での必要に応じて、ビューの結果から、LastLoggedInAt
値がNULL
である行が除外されていることに注意してください。
SELECT
基になるテーブルに対する2番目のステートメントはエラーを返します。
メッセージ229、レベル14、状態5、行28
SELECT権限がオブジェクト 'LoginDetails'、データベース 'tempdb'、スキーマ 'dbo'で拒否されました。
掃除:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
または、SQL Server 2016以降を使用している場合は、行レベルのセキュリティ述語を使用して、特定のユーザーにNULL LastLoggedInAt
値の行が表示されないようにすることができます。
まず、テーブル、ログイン、そのログインのユーザーを作成し、テーブルへのアクセスを許可します。
CREATE TABLE dbo.LoginDetails
(
Username nvarchar(100) NOT NULL
, EmailAddress nvarchar(256) NOT NULL
, LastLoggedInAt datetime NULL
);
GO
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetails TO RemoteUser;
次に、いくつかのサンプル行を挿入します。nullを持つ1つの行と、その列にnull LastLoggedInAt
以外の値を持つ1つの行。
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
ここでは、関数に渡された変数@LastLoggedInAt
と@username
変数の値に応じて0または1の行を返すスキーマバインドテーブル値関数を作成しています。この関数は、特定のユーザーに対して非表示にする行を除外するために、フィルター述語によって使用されます。
CREATE FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate
(
@LastLoggedInAt datetime
, @username sysname
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE (@username = N'RemoteUser' AND @LastLoggedInAt IS NOT NULL)
OR @username <> N'RemoteUser';
GO
これは、テーブルSELECT
に対して実行されたステートメントから行を削除するセキュリティフィルターですdbo.LoginDetails
。
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
上記のフィルターdbo.fn_LoginDetailsRemoteUserPredicate
は、現在のユーザーの名前とLastLoggedInAt
、dbo.LoginDetails
テーブルの列の各行の値を渡すことにより、関数を使用します。
通常のユーザーとしてテーブルをクエリすると:
SELECT *
FROM dbo.LoginDetails
すべての行が表示されます。
╔══════════╦══════════════╦═══════════════════════ ══╗ ║ユーザー名║メールアドレス║LastLoggedInAt║ ╠══════════╬══════════════╬═══════════════════════ ══╣ ║ユーザーx║x@y.com║NULL║ ║ユーザーy║y@y.com║2018-02-15 13:53:42.577║ ╚══════════╩══════════════╩═══════════════════════ ══╝
ただし、次のようにテストした場合RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
「有効な」行のみが表示されます。
╔══════════╦══════════════╦═══════════════════════ ══╗ ║ユーザー名║メールアドレス║LastLoggedInAt║ ╠══════════╬══════════════╬═══════════════════════ ══╣ ║ユーザーy║y@y.com║2018-02-15 13:42:02.023║ ╚══════════╩══════════════╩═══════════════════════ ══╝
そして、私たちはクリーンアップします:
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
この方法で関数をテーブルにスキーマバインドすると、最初にフィルター述語とdbo.fn_LoginDetailsRemoteUserPredicate
関数を削除せずにテーブルの定義を変更できなくなることに注意してください。
LastLoggedInAt
列に有用なインデックスを作成した場合、パフォーマンスへの影響はごくわずかです。