Le modèle de sécurité SQL Server vous permet d'accorder l'accès à une vue sans accorder l'accès aux tables sous-jacentes.
Étant donné que l'exemple de code est un excellent moyen de montrer un concept, considérez ce qui suit, avec une LoginDetails
table et la vue correspondante:
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
Nous allons créer une connexion et un utilisateur, puis attribuer à cet utilisateur les droits pour sélectionner des lignes dans la vue, sans avoir le droit de visualiser la table elle-même.
CREATE LOGIN RemoteUser
WITH PASSWORD = '2q1345lkjsadfgsa0(*';
CREATE USER RemoteUser
FOR LOGIN RemoteUser
WITH DEFAULT_SCHEMA = dbo;
GRANT SELECT ON dbo.LoginDetailsView TO RemoteUser;
Maintenant, nous allons insérer deux lignes de test:
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Cela teste le modèle de sécurité. La première SELECT
instruction réussit, car elle sélectionne dans la vue, tandis que la deuxième SELECT
instruction échoue parce que l'utilisateur n'a pas d'accès direct à la table.
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetailsView;
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nom d'utilisateur ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ utilisateur y ║ y@y.com ║ 2018-02-15 07: 36: 54.490 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
SELECT *
FROM dbo.LoginDetails;
REVERT
Notez que les résultats de la vue excluent la ligne où se trouve la LastLoggedInAt
valeur NULL
, comme requis dans votre question.
La deuxième SELECT
instruction sur la table sous-jacente renvoie une erreur:
Msg 229, niveau 14, état 5, ligne 28
L'autorisation SELECT a été refusée sur l'objet 'LoginDetails', base de données 'tempdb', schéma 'dbo'.
Nettoyer:
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP VIEW dbo.LoginDetailsView;
DROP TABLE dbo.LoginDetails;
Alternativement, si vous avez SQL Server 2016 ou une version plus récente, vous pouvez utiliser un prédicat de sécurité de niveau ligne pour empêcher certains utilisateurs de voir des lignes avec une LastLoggedInAt
valeur NULL .
Tout d'abord, nous créons la table, une connexion, un utilisateur pour cette connexion, et nous accordons l'accès à la table:
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;
Ensuite, nous insérons quelques exemples de lignes. Une ligne avec une valeur nulle LastLoggedInAt
et une avec une valeur non nulle pour cette colonne.
INSERT INTO dbo.LoginDetails(Username, EmailAddress, LastLoggedInAt)
VALUES ('user x', 'x@y.com', NULL)
, ('user y', 'y@y.com', GETDATE());
Ici, nous créons une fonction table de valeur liée au schéma qui renvoie une ligne avec 0 ou 1 selon la valeur des variables @LastLoggedInAt
et @username
qui sont passées dans la fonction. Cette fonction sera utilisée par un prédicat de filtre pour éliminer les lignes que nous voulons cacher à certains utilisateurs.
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
Il s'agit du filtre de sécurité qui élimine les lignes des SELECT
instructions exécutées sur la dbo.LoginDetails
table:
CREATE SECURITY POLICY LoginDetailsRemoteUserPolicy
ADD FILTER PREDICATE dbo.fn_LoginDetailsRemoteUserPredicate(LastLoggedInAt, USER_NAME())
ON dbo.LoginDetails
WITH (STATE=ON);
Le filtre ci-dessus utilise la dbo.fn_LoginDetailsRemoteUserPredicate
fonction en transmettant le nom de l'utilisateur actuel, ainsi que les valeurs de chaque ligne pour la LastLoggedInAt
colonne de la dbo.LoginDetails
table.
Si nous interrogeons la table en tant qu'utilisateur normal:
SELECT *
FROM dbo.LoginDetails
nous voyons toutes les lignes:
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nom d'utilisateur ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ utilisateur x ║ x@y.com ║ NULL ║
║ utilisateur y ║ y@y.com ║ 2018-02-15 13: 53: 42.577 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Cependant, si nous testons comme RemoteUser
:
EXECUTE AS LOGIN = 'RemoteUser';
SELECT *
FROM dbo.LoginDetails
REVERT
nous ne voyons que les lignes "valides":
╔══════════╦══════════════╦═══════════════════════ ══╗
║ Nom d'utilisateur ║ EmailAddress ║ LastLoggedInAt ║
╠══════════╬══════════════╬═══════════════════════ ══╣
║ utilisateur y ║ y@y.com ║ 2018-02-15 13: 42: 02.023 ║
╚══════════╩══════════════╩═══════════════════════ ══╝
Et nous nettoyons:
DROP SECURITY POLICY LoginDetailsRemoteUserPolicy;
DROP FUNCTION dbo.fn_LoginDetailsRemoteUserPredicate;
DROP USER RemoteUser;
DROP LOGIN RemoteUser;
DROP TABLE dbo.LoginDetails;
N'oubliez pas que la liaison de schéma d'une fonction à la table de cette manière ne permet pas de modifier la définition de la table sans supprimer au préalable le prédicat de filtre et la dbo.fn_LoginDetailsRemoteUserPredicate
fonction.