Динамическое маскирование данных с помощью динамического фильтра строк в табличном SSAS

#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:

  1. Отключите UNION он игнорирует контекст фильтра и ваши RLS. Используйте LOOKUPVALUE , чтобы убедиться, что пользователь имеет доступ к строкам на EmployeeMasked основе, если они EmployeeKey существуют на EmployeeAuthorized

  2. Отредактируйте свою EmployeeAuthorized таблицу, чтобы она содержала ADUsername столбец. Для каждого ключа EmployeeKey сохраните их значение ADUsername, которое будет возвращено из функции dax USERNAME()

  3. Отредактируйте созданную вами роль и перейдите на вкладку Фильтры строк.

  4. Найдите таблицу EmployeeMask

  5. Добавьте следующий фильтр 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()
  

В результате:

введите описание изображения здесь