#sql-server #dax #ssas-tabular
#sql-сервер #dax #ssas-табличный
Вопрос:
Я пытаюсь реализовать способ использования динамического маскирования данных при табличном импорте SSAS. По умолчанию это не поддерживается в службах SQL Server Analysis Services 2016 (насколько я знаю). Я думаю, что я нашел способ реализовать это в любом случае, используя безопасность на уровне динамических строк. Однако мои результаты не соответствуют ожиданиям.
Мой случай — таблица Employee. Он содержит примерно 2000 строк, моему тестовому пользователю разрешено просматривать около 50. Я импортировал таблицу Employee, добавил таблицу безопасности (EmployeeKey, имя пользователя) и установил фильтр строк в таблице Employee. Более или менее аналогично образцу от Microsoft.
Кроме того, я добавил таблицу с именем EmployeeMask, которая содержит те же 2000 строк, с теми же EmployeeKeys и теми же столбцами. Однако я «замаскировал» значения остальных столбцов.
Используя запрос многомерных выражений, выдаваемый за моего тестового пользователя, я извлекаю 50 сотрудников из моей таблицы Employee и 2000 сотрудников из моей таблицы EmployeeMask. Пока все хорошо. Теперь начинается та часть, где я думал, что я умный. Я переименовал свою таблицу EmployeeAuthorized в EmployeeAuthorized и добавил вычисляемую таблицу Employee следующим образом:
=UNION(
EmployeeAuthorized;
FILTER(
EmployeeMask;
LOOKUPVALUE(EmployeeAuthorized[EmployeeKey]; EmployeeAuthorized[EmployeeKey]; EmployeeMask[EmployeeKey])
= BLANK()
)
)
Однако, используя запрос многомерных выражений к моей новой вычисляемой таблице Employee, я получаю все 2000 строк без масок. Я предполагаю, что вычисляемая таблица обрабатывается заранее, тогда как я думал, что DAX-формула будет выполняться по запросу. Верно ли мое предположение? Есть ли способ соответствовать моим требованиям?
Пример данных:
CREATE TABLE [dbo].[Employee] (--Renamed this to EmployeeAuthorized
[EmployeeKey] INT NOT NULL,
[EmployeeName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[Employee] VALUES
(1, 'A A'), (2, 'B B'), (3, 'C C');
CREATE TABLE [dbo].[Fact] (
[EmployeeKey] INT NOT NULL,
[Value] INT NOT NULL
);
INSERT INTO [dbo].[Fact] VALUES
(1, 1), (2, 2), (3, 5), (3, 8);
CREATE TABLE [dbo].[Security] (
[EmployeeKey] INT NOT NULL,
[UserName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[Security] VALUES
(1, 'domainu1'), (2, 'domainu1'), (3, 'domainu1'),
(1, 'domainu2');
И при необходимости:
CREATE TABLE [dbo].[EmployeeMask] (
[EmployeeKey] INT NOT NULL,
[EmployeeName] VARCHAR(50) NOT NULL
);
INSERT INTO [dbo].[EmployeeMask] VALUES
(1, 'masked'), (2, 'masked'), (3, 'masked');
Я пытаюсь выполнить следующее:
Ответ №1:
-
Отключите
UNION
он игнорирует контекст фильтра и ваши RLS. ИспользуйтеLOOKUPVALUE
, чтобы убедиться, что пользователь имеет доступ к строкам наEmployeeMasked
основе, если ониEmployeeKey
существуют наEmployeeAuthorized
-
Отредактируйте свою
EmployeeAuthorized
таблицу, чтобы она содержалаADUsername
столбец. Для каждого ключа EmployeeKey сохраните их значение ADUsername, которое будет возвращено из функции daxUSERNAME()
-
Отредактируйте созданную вами роль и перейдите на вкладку Фильтры строк.
-
Найдите таблицу EmployeeMask
-
Добавьте следующий фильтр DAX, чтобы Роль обеспечивала, чтобы пользователи, принадлежащие к роли, могли видеть строки в EmployeeMask только в том случае, если их EmployeeKey / ADUsername имеют соответствующие записи авторизации поиска в EmployeeAuthorizedy.
=EmployeeMask[EmployeeKey]
=LOOKUPVALUE(
EmployeeAuthorizedy[EmployeeKey],
EmployeeAuthorized[EmployeeKey], EmployeeMask[EmployeeKey],
EmployeeAuthorized[ADUsername], USERNAME()
)
Комментарии:
1. Извините за (очень) поздний ответ. Либо я немного запутался, либо это не сработает. Моя таблица безопасности имеет много-много-отношений между сотрудником и пользователем (поскольку мой пример пользователя должен иметь доступ примерно к 50 сотрудникам). Поэтому я не думаю, что возможно добавить AD-username непосредственно в таблицу, авторизованную моим сотрудником.
Ответ №2:
Я смог решить эту головоломку следующим образом:
Я импортировал таблицы в свою табличную модель SSAS. Я дважды импортировал таблицу Employee, один раз как Employee и один раз как EmployeeKey, используя только столбец EmployeeKey.
Как вы можете видеть, взаимосвязи заключаются в следующем:
Fact[EmployeeKey] *:1 (<< To Fact) EmployeeKey[EmployeeKey]
Employee[EmployeeKey] *:1 (<< To Both Tables >>) EmployeeKey[EmployeeKey]
Security[EmployeeKey] *:1 (<< To Security) Employee[EmployeeKey]
Я добавил единственную роль с разрешениями на чтение и следующими фильтрами строк:
Table Employee: =Employee[EmployeeKey]=LOOKUPVALUE(Security[EmployeeKey]; Security[UserName]; USERNAME(); Security[EmployeeKey]; Employee[EmployeeKey])
Table Security: =FALSE()
В результате: