PowerBI 实现不同角色看到内容不同支持动态权限管理

合适合理的人可以看相应的报告数据,如果不具备地区(店铺)的权限,数据计算会自动适应。这个功能在PowerBI中又叫做:动态权限控制。这需要根据登陆的用户的不同来决定它的计算。但本文的讨论将远远超过这个基本需求,将现实中几种复杂需求进行讨论并给出解决方法。

用行级别安全性实现动态权限控制

首先看看默认的正常效果是什么:

在带有权限控制的情况下,效果就不是这样了,例如有多个地区销售,不同的大区经理登录时,应该只能看到他自己的情况。我们希望的效果很简单,那就是在某个用户登录PowerBI后,只看到属于他的结果:

我们使用了欢迎信息,并只显示了属于楚杰的内容。这样的效果可以在PowerBI中通过行级别安全性来实现。这样基本可以满足需求。

首先,在PowerBIDesktop中进行设计,先设计一个权限表:

具体权限如下:

也就是说,这些用户账号在PowerBIService登录时,会分别代表这些用户,接下来会使用一个很重要的动态函数:USERNAME()来动态地获取当前登录的用户名,并设置角色的安全性如下:

这里的意思是:对于负责人角色,按照权限表来进行过滤,过滤的条件是[PowerBI账号] 在 { [用户 当前用户] }中。其中,[用户 当前用户]是度量值:

这样,在PowerBIDesktop端就完成了权限的设计,将这些内容发布到云端之前,云端需要一些准备。

首先,我们使用一个工作区来容纳我们的内容,并做基本的权限设定:

我们用三个用户来做演示:

注意,管理员和成员有不同的权限:

  • 管理员,可以访问并编辑工作区内的内容。
  • 成员,只能查看工作区内的内容。

由于管理员可以编辑工作区内的内容,这个权限非常大,所以行级别安全性(RLS)对管理员是不起作用的,这也符合逻辑,因为管理员是发布PowerBI文件的人,也就是开发或设计PowerBI文件的人,他显然可以查看文件的任何内容,不然也无法发布。

因此,真正的权限控制的前提是针对成员进行的,需要将该工作区的用户全部作为成员添加,而不能赋予管理员的权限,且成员只能查看 Power BI 内容。

接着我们需要在云端的数据集进行设置,如下:

这样,我们就可以在某类角色下,把相关的用户装入进来,之前在Desktop中设置的安全性就可以生效了。

我们使用[email protected]登录来看看效果:

这是满足我们需要的。小结一下,我们可以发现这种方法是针对角色来设置行级别安全性,通过USERNAME函数动态获得用户名并对数据进行筛选,由于模型的关系会将筛选进行传递,使得特定的用户只能计算属于他的数据进而起到了数据隐私保护的作用。

自主全动态安全性控制

在上述的行级别安全性中已经解决了很多问题,可以应付N家门店店长加入店长角色后,就只能看到自己的数据计算。

问题来了,如果想给店长显示一个全局平均线怎么办,希望的效果如下:

就会发现上述的行级别安全性做法就不行了,因为在加载数据的时候已经过滤掉了所有不属于该用户的数据,如果再回头观察下刚刚的行级别安全性方法下的报告,会发现我的销售额全部销售额的值是一样的,及时用了ALL函数也无济于事。原因也是因为此,即只加载和此人权限有关的数据了,因此ALL的数据也只有这些数据,固结果是一样的。但这不是我们想要的,我们预期的效果要满足两点:

  • 能看到我的销售额(即:带权限的销售额)
  • 全局平均销售区域销售额来做参照对比

通过这样的分析,就发现不能使用行级别安全性来实现,因为这将过滤全部数据,只剩下一部分,也就无法计算全局结果。所以我们必须自主实现带权限的计算,并加载全部数据。

如果做一些实践,我们不难发现,行级别安全性的本质在于按照角色来过滤数据,其实数据集的全部数据并没有变化,既然如此,我们也可以自己来写带权限的度量值,达到一样的效果。例如,常规的销售额写法如下:

销售 销售额 = SUM( '订单'[销售额] )

而带权限的写法是:

销售 销售额 带权限 = CALCULATE( [销售 销售额] , FILTER( '权限表' , '权限表'[PowerBI账号] = [用户 当前用户] ) )

在这种写法下,我们并不需要设置行级别安全性,安全性由我们自己控制。我们反而需要关闭行级别安全性,以免受到影响,而实现了预期的效果。

用这种方法与行级别安全性来做个对比:

  • 本方法可以实现对当前用户权限控制,并计算非当前用户下的数据,更加灵活;而行级别安全性只能计算当前用户下的数据。
  • 本方法需要将报告中已经使用的度量值,全部换成加入权限控制的度量值,如果已经使用了几百个度量值,再全部替换,是一个很大的工作量;而行级别安全性不涉及对度量值的修改,没有额外工作量。

我们再次感受了有得必有失的无奈啊,行级别安全性和自主全动态安全性各有优劣,如果真的存在以下这种情况:

  • 有大量度量值,全部修改的工作量太大。
  • 必须要和全局度量值计算对比之类的需求,行级别安全性会过滤数据无法满足。

我们提供一个思路,可以同时解决上述两个问题,那就是:

  • 重复加载相关的事实表,让重复加载的事实表不受行级别安全性的影响。
  • 对需要特定处理的全局计算使用这些不受影响的事实表。

当然,解决了两个痛点的同时又带来了一个问题,那就是数据被重复加载了,导致了冗余,也算是一种不完美,在实际环境中,根据实际问题来权衡处理才是合适的。这里的讨论已经足够充分,可以应对不同的场景了。

控制可以展示的报告页面

以上的权限控制属于一套类型,或者说是一种角度。另一种角度,在PowerBI中是没考虑的场景,但在现实中却有这样的需求,那就是:不同的角色可以看到的页面数是不同的。例如:一份报告有10页,CEO可以看到所有页面;而区域负责人不能看到公司总体报告页面。也就是,不同的用户能显示或隐藏不同的页面。

很显然这个需求在PowerBI中默认又是无法做到的,这里给出一个思路,可以应对这种很有现实意义但又没有官方支持的场景。思路如下:

  • 默认将页面全部隐藏。
  • 通过导航或链接的方式决定用户能去哪些页面。

如下,例如用[email protected]作为CEO身份:

由于页面都是隐藏状态,他可以通过链接的形式浏览到不同的页面。实际在WEB看到的效果是:

只显示了首页,用户必须通过导航去浏览各个页面。 对于非CEO的楚杰,他可能浏览的权限页面如下:

他并不能浏览PageC页面。

以上这些巧妙的设计,需要两个表来辅助完成:

  • 页面列表,列出了所有的页面以及页面的地址。
  • 权限页面控制,列出了哪些PowerBI账号可以看哪些页面。

我们在报告中用表来显示这个结构的时候,利用了PowerBI的一个技巧,那就是如果值为空(BLANK),会自动隐藏该行,这样我们就巧妙地隐藏了没有权限的页面:

这里又使用了一个技巧,那就是:我们来判断每个页面是否是被当前用户预设的权限表所允许的,如果允许就返回””空白字符,如果不允许就返回空来隐藏。空白字符也起到了一种效果,就是显示页面和链接属性却没有视觉上的值,达到了预期的效果。

这种巧妙的设计灵活地使用了PowerBI各种能力,来弥补它的缺陷。经过测试发现这种方法有两个缺陷,那就是:

  • 发布后要准备好各个页面的实际URL地址备用。
  • 在WEB点击后会打开新浏览器页而不是在当前页跳转。

针对这两个问题可以进一步优化,限于我们已经钻入太深,这里仅给出思路:标签。由于标签也有跳转效果,我们可以针对不同的角色制作不同的标签跳转体系,结合这里的链接权限方法,就可以免除90%记录URL以及新开浏览器页的问题,几乎可以完美解决问题。

总结

我们这里讨论了三种场景下PowerBI灵活动态控制权限的方法,以满足多个角色多个数据权限的自动化控制:

  • 不同用户的指标计算依据他的数据进行,PowerBI内置的行级别安全性(RLS),并借助USERNAME实现动态权限控制。
  • 显示当前用户计算并同时包含某些全局计算,自主全动态安全性控制,关闭RLS并完全借助筛选来实现这一灵活控制,实际中还可以和RLS结合。
  • 向不同的用户显示不同的报告页面(数),借助链接和标签以及安全性实现控制。

另外,值得一提的是,如果将PowerBI与SSAS(内置于SQL Server 2017或Azure Analysis Service中)结合的话,可以控制某张表或某个列对用户的权限,也就是用户可以看不到不希望他看到的表或列,这为自助分析的有效控制又提供了更加细致的方案。