在Power BI中开发和测试RLS规则
很多时候,并不是所有的用户都应该有权限访问报告中的所有数据。在这里,我将解释如何开发Power BI中的RLS规则来配置访问权限以及如何测试它们。
介绍
我的许多客户都希望基于特定规则限制其报告中的数据访问权限。
访问数据称为行级安全性(简称RLS)。
你可以在小猪AI上找到许多关于Power BI中RLS的文章。
我在下面的参考资料中添加了其中的两篇。
虽然所有文章都很好地解释了基础知识,但我总是缺乏如何开发更复杂的规则以及如何轻松测试它们的解释。
在本文中,我将解释RLS的基础知识并逐步添加复杂性。
此外,我还将向你展示如何使用DAX Studio构建查询以在将其添加到数据模型之前测试RLS规则。
所以,我们开始吧。
场景
我使用场景,即基于店铺或公司内店铺的地理位置,包括两者的组合,用户可以访问零售销售数据。
在Contoso数据模型中,我使用以下表:
我创建以下报告以测试我的结果:
创建一个简单的规则
要创建RLS规则,你需要打开安全角色编辑器:
接下来,你可以创建一个新角色并设置此角色的名称:
在我的情况下,我将名称设置为“StorePermissions”。
现在,我可以开始添加表达式来控制对Store表的访问:
我们已经有了一个新的、更简单的RLS规则编辑器。
在我的情况下,我想添加一个DAX表达式。所以我点击“切换到DAX编辑器”按钮。
首先,我添加最简单的表达式:TRUE()
要理解RLS规则,您必须知道访问是由RLS规则编辑器中表达式的输出控制的。
如果表达式的输出不为空或FALSE(),则用户将获得访问权限。
原则上,RLS规则编辑器中的任何表达式都会被添加为任何查询的过滤器。在我更详细地解释之前,让我们先看一下这个第一个表达式的效果。
为了测试该规则,我保存表达式并关闭编辑器。
现在我可以使用新规则查看报告:
在报告页面顶部,您将看到一个黄色横幅,显示您正在使用StorePermission规则查看报告。
由于StorePermission规则不限制访问,因此您不会看到任何差异。
让我们尝试些不同的东西。
现在我将RLS规则中的表达式更改为FALSE()。
当我测试该规则时,我将不会看到任何数据:
这证明如果表达式不返回FALSE(),则可以访问数据。
测试查询
要详细了解此效果,请让我展示一个DAX查询,以获取不受任何限制的结果:
EVALUATE SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] )ORDER BY Store[Store]
当我添加一个如上所示的TRUE()的RLS规则时,查询会变成类似于以下查询:
EVALUATE FILTER( SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] ) ,TRUE() )ORDER BY Store[Store]
我将查询包含在FILTER()函数中,并将TRUE()作为过滤器表达式添加。
在接下来的示例中,我将使用CALCULATETABLE(),因为编写代码更有效和灵活。
稍后再详细说明。
让它变得更加复杂
接下来,我想限制访问所有包含“Contoso T”字符串的商店。
为此,我将规则编辑器中的表达式更改为以下内容:
CONTAINSSTRING('Store'[Store], "Contoso T")
测试规则时,我会得到以下结果:
使用DAX查询测试规则
使用DAX Studio中的以下查询检查结果会很好:
EVALUATE CALCULATETABLE( SUMMARIZECOLUMNS( Store[Store] ,"Retail_Sales", 'All Measures'[Retail Sales] ) CONTAINSSTRING('Store'[Store], "Contoso T") = TRUE() )ORDER BY Store[Store]
内部部分使用SUMMARIZECOLUMNS()生成输出表格。
在本例中,我只对商店列表感兴趣。
然后,我使用CALCULATETABLE()将SUMMARIZECOLUMNS()调用封装起来,以添加查询过滤器。
在本例中,我添加了RLS规则中的表达式,包括“= TRUE()”检查。
结果如下:
但是,在幕后会发生什么?
让我们看看存储引擎查询:
当我将RLS规则应用于此查询时会发生什么?
我可以使用DAX Studio中的几个点击应用RLS规则:
存储引擎查询如下:
第一个查询(第2行)检索所有商店的列表。
第二个查询将RLS规则包含在WHERE子句中。
我们不再看到匹配商店列表(根据过滤器),而是看到一个包含RLS规则的加密行。
您可以看到存储引擎(SE)查询的结果仍然包含309行,就像上面一样,这是所有商店的数量+ 3行。我们为什么有3行差异的提示在SE查询下面的文本中:估计大小:行= 309
实际返回的行数可能确实为306。
但是,该分析表明RLS规则在存储引擎之后应用,因为查询结果仅包含21行:以“Contoso T”开头的所有商店。
这很重要,因为公式引擎(FE)在存储引擎之后计算最终结果,并且是单线程的,只能使用一个CPU核心。
而SE是多线程的,可以使用多个CPU核心。
因此,我们必须避免在RLS规则中编写低效的代码。
组合规则
接下来,我想组合两个表达式:
- 仅以“Contoso T”开头的商店
- 仅在欧洲的商店
为此,我使用简单编辑器向地理表添加第二个表达式:
当我切换到DAX编辑器时,我得到以下表达式:
注意使用严格相等运算符。
更改表达式的简单等号运算符可能是必要的。
这是测试规则时的结果:
此规则的DAX查询如下:
现在,让我们给RLS规则增加另一层复杂性:
我想限制访问以下商店:
- 名称以“Contoso T”开头且在欧洲的商店或
- 名称以“Contoso S”开头并在北美洲的商店
这次,我从DAX查询开始。这是开发和测试表达式的简单方法。
我使用过滤表达式取第一个查询并将其括在其中。
由于我需要过滤两个表(Store和Geography),因此必须使用FILTER()和RELATED():
EVALUATE CALCULATETABLE( ADDCOLUMNS( SUMMARIZECOLUMNS(Store[Store], 'Geography'[Continent]) ,"Retail_Sales", 'All Measures'[Retail Sales] ) ,FILTER(Store ,OR(CONTAINSSTRING('Store'[Store], "Contoso T") && RELATED(Geography[Continent]) = "Europe" ,CONTAINSSTRING('Store'[Store], "Contoso S") && RELATED(Geography[Continent]) = "North America") ) )ORDER BY [Retail Sales] DESC, 'Geography'[Continent], Store[Store]
由于我使用FILTER()迭代Store表,因此需要RELATED()函数,并且需要来自Geography表的Continent列。
由于Geography表位于关系的一侧,因此我可以使用RELATED()获取Continent列。
这是结果:
接下来,我们必须将此过滤器转换为RLS规则。
对于RLS规则,我们可以删除FILTER()函数,因为RLS规则本质上作为过滤器工作。
请注意,我已从“地理”表中删除了表达式。
当我在Power BI中测试此规则时,我得到了以下结果,这与DAX查询的结果相对应:
为了测试RLS规则,例如当您仅想获取经过过滤的商店列表时,您可以编写只有FILTER()函数的简单查询:
基于用户登录配置访问权限
到目前为止,我们已经了解了静态的RLS规则。
但是大多数情况下,我们需要基于用户登录的规则。
为了实现这一点,我们需要一个表来映射用户到用户需要访问的行。
例如,像这样的表:
将该表添加到数据模型后,我们需要在新表和“地理位置”表之间添加关系:
新的“地理位置访问”表与“地理位置”表之间的关系必须正确配置。
添加关系后,Power BI将其配置为1:n关系,其中一侧为“地理位置”表,过滤器从“地理位置”表流向“地理位置访问”。
但是,我们希望基于“地理位置访问”的RLS规则(过滤器)过滤“地理位置”表。出于这个原因,我们必须将交叉筛选方向更改为“both”:
此外,我们必须在“两个方向上应用安全筛选器”上设置标志,因为Power BI在应用RLS规则时忽略交叉筛选方向设置。
现在我们可以添加RLS规则:
添加此规则之前,请记得删除Store表上的任何过滤表达式。
测试RLS规则时,我得到了这个:
为了找出发生了什么,请返回RLS规则编辑器,并将规则的视图更改为DAX:
简单的RLS规则编辑器无法识别DAX函数,并将其作为文本添加到过滤器中。
我们必须将表达式更改为:
现在结果与预期相同:
报告页面左上角的卡片包含一个使用USERPRINCIPALNAME()函数确保正确用户在测试期间处于活动状态的度量。
我甚至可以使用另一个用户测试RLS规则:
有趣的是,这个用户不需要存在,只需要包含在“地理访问”列表中。
这是测试的结果:
在顶部的黄色行中,您可以看到测试期间的活动用户。
结论
我向您展示了如何创建基本的RLS规则以及如何测试它们。
然后我增加了更多的复杂性,分析了RLS规则对底层存储引擎的影响。
我们已经看到公式引擎处理RLS规则的一部分。因此,我们必须在RLS规则中编写高效的代码。
在将RLS规则实施到数据模型之前,了解如何测试RLS规则非常重要。
通过了解规则如何应用于数据模型,更容易理解错误的结果。
最后,我向模型添加了动态的基于用户的RLS规则。
这些规则在DAX查询中更难测试,因为您必须知道每个用户可以访问哪些数据,以编写正确的测试查询以验证结果。
我希望我已经为您提供了一些关于在Power BI中使用RLS功能简化生活的提示。
参考资料
您可以在本文中找到Power BI中的安全功能列表:
Power BI中的4 + 2个安全功能
在此主题上发表第一篇文章一年后,更新了Power BI中的新安全功能
towardsdatascience.com
您可以在Power BI(现在是Fabric)社区页面上找到有关Power BI中行级安全性的简单说明:Row-level security (RLS) with Power BI — Power BI | Microsoft Learn。
我可以推荐Nikola Ilic撰写的这篇文章,其中您可以了解有关RLS的起点:
Power BI中行级和对象级安全性的终极指南
“报告中谁看到什么?”是Power BI中的关键安全问题之一。学习两种可能的实现方法……
towardsdatascience.com
Elias Nordlinder撰写的另一篇有关Power BI中行级安全性的入门文章:
如何在Power BI中实现行级安全性(第I部分)
行级安全性是一种根据不同角色以不同方式过滤数据的方法。这可能是静态完成的……
elias-nordlinder.medium.com
访问我的故事列表,了解有关FILTER()函数以及如何使用DAX Studio分析DAX查询的更多信息。
我使用了像我之前的文章中一样的Contoso样本数据集。您可以从Microsoft这里免费下载ContosoRetailDW数据集。
Contoso数据可在MIT许可下自由使用,如此处所述。
使用我的推荐链接加入小猪AI – Salvatore Cagliari
作为小猪AI会员,您的会员费的一部分将用于支付您所阅读的作家,并且您将获得对每个故事的完全访问权限…
小猪AI.com