Одна из интересных новинок в SQL Server 2016 - это Row-Level Security (RLS). Технология RLS (row-level security или безопасность на уровне строк) предоставляет возможность создания политик безопасности, которые ограничивают доступ пользователям к информации в БД.
Данная технология поддерживается во многих современных СУБД, но, к сожалению, в предыдущих версиях SQL Server реализовать RLS было не самой простой задачей. На сайте Microsoft есть целый документ, как это реализовать - http://download.microsoft.com/download/8/8/0/880F282A-AA4E-4351-83C0-DFFA3B56A19E/SQL_Server_RLS-CLS_White_paper.docx
Теперь рассмотрим, как это реализовано в SQL Server 2016
Создадим тестовую таблицу и наполним её данными:
if object_id ( N'dbo.TestRLS', N'U' ) is not null
drop table dbo.TestRLS;
go
create table dbo.TestRLS ( id int identity
, UserName sysname
, Val int
);
go
insert dbo.TestRLS
values ( 'User1', 11 )
, ( 'User1', 12 )
, ( 'User1', 13 )
, ( 'User2', 21 )
, ( 'User2', 22 )
;
go
select * from dbo.TestRLS;
go
Технология RLS состоит из 3-х компонентов:
Predicate function - Пользовательская функция описывает логику безопасности
Security predicate - Применяет предикат к конкретной таблице. Два типа: filter predicates and blocking predicates
Security policy - Коллекция предикатов для нескольких таблиц
Теперь создадим 2-х пользователей и дадим им права на чтение нашей таблицы
create user User1 without login;
create user User2 without login;
go
grant select on dbo.TestRLS to User1;
grant select on dbo.TestRLS to User2;
go
Создадим функцию (Predicate function), которая будет определять права
create function dbo.fn_securitypredicate(@user_name as sysname)
returns table
with schemabinding
as
return select 1 as fn_securitypredicate_result
where @user_name = user_name();
go
И теперь по имени пользователя будем определять, какие данные нам доступны:
create security policy rls_plicy
add filter predicate dbo.fn_securitypredicate(UserName)
on dbo.TestRLS
with (state = on);
go
Посмотрим, какие данные видны в контексте каждого пользователя:
--Текущий пользователь
select user_name() as [user_name];
go
select * from dbo.TestRLS;
go
--Перевлючаем в контекст пользователя User1
execute as user = 'User1';
go
select user_name() as [user_name];
go
select * from dbo.TestRLS;
go
revert;
go
--Перевлючаем в контекст пользователя User2
execute as user = 'User2';
go
select user_name() as [user_name];
go
select * from dbo.TestRLS;
go
revert;
go
Всё достаточно легко и просто!