我想要一些关于最佳实践的建议。
我正在维护SSRS报告服务器,现在需要支持多家公司。每家公司都应该只看到自己的数据。母公司应该能够看到所有数据,但也能够由子公司分开。
有些报告是相同的,只是查看整体数据的不同子集。
实现这一目标的最佳方法是什么,确保数据只能由相应的公司访问,以及我可以轻松更新报告等,以及稍后添加新公司?
我目前正在建设"核心"报告,然后使用带有公司名称的链接报告作为隐藏的默认参数。
或者,我考虑使用主数据的过滤视图为每个公司创建单独的数据库。那么我将改变源代码而不是参数。
我意识到这是一个悬而未决的问题,但想要了解更多有经验的人的利弊,然后才开始这样做。
答案 0 :(得分:2)
有几种方法可以解决这个问题:
假设这对于可以访问组合数据库的内部人员来说不是安全问题,最简单的是组合数据库,并且报告中包含逻辑,以确保人们只能看到他们被允许的公司。
这里有两个问题:
Reporting Services使用@UserId
全局变量为您解决了第一个问题。
我假设你有一张表Company
看起来像这样:
CompanyId | Name | ParentCompanyId
----------+-------------+----------------
1 | ABC Inc. |
2 | DEF Co. | 1
3 | GHI Ltd. | 1
4 | XYZ Corp. |
我们需要一种将其映射到他们可以运行报告的公司的方法,因此我们创建了一个包含UserId
和CompanyId
字段的表格,以便将用户映射到他们的公司。
UserId | Name | CompanyId
----------+-------------+----------
10 | Alyssa | 1
20 | David | 2
30 | Gloria | 3
40 | Xavier | 4
所以Alyssa可以看到ABC公司和子公司DEF Co和GHI Ltd,而大卫只能看到DEF Co,Gloria只能看到GHI有限公司和Xavier只能看到XYZ公司。
在报告中,您可以根据关系选择数据:
SELECT Invoices.CompanyId, Invoices.Number, Invoices.Date, Invoices.Amount
FROM Invoices
INNER JOIN Companies ON Invoices.CompanyId = Companies.CompanyId
INNER JOIN Users ON Users.UserId = @UserId
AND ((Companies.CompanyId = Users.CompanyId) OR (Companies.ParentCompanyId = Users.CompanyId))
好的,这需要确保用户只能看到与用户关联的公司和子公司的数据:David只能查看DEF Co的发票,而Alyssa会查看ABC Inc,DEF的所有发票Co和GHI有限公司
现在,如果Alyssa只想看DEF Co,她需要能够选择那家公司。根据此查询创建@CompanyId
参数:
SELECT Companies.CompanyId, Companies.Name
FROM Companies
INNER JOIN Users ON Users.UserId = @UserId
AND ((Companies.CompanyId = Users.CompanyId) OR (Companies.ParentCompanyId = Users.CompanyId))
这显示了用户可以选择的所有公司。设置参数的默认值以从查询中获取其值:
SELECT CompanyId FROM Users WHERE UserId = @UserId
然后我们将此参数添加到我们的查询中:
SELECT Invoices.CompanyId, Invoices.Number, Invoices.Date, Invoices.Amount
FROM Invoices
INNER JOIN Companies ON Invoices.CompanyId = Companies.CompanyId
INNER JOIN Users ON Users.UserId = @UserId
AND ((Users.CompanyId = Companies.CompanyId) OR (Users.CompanyId = Companies.ParentCompanyId))
AND ((@CompanyId = Companies.CompanyId) OR (@CompanyId = Companies.ParentCompanyId))
报告订阅
现在我们开始通过订阅提交报告,我们围绕使用@UserId
的策略分崩离析,因为报告调度程序在自己的帐户下运行报告,而不是我们想要定位的用户。
让我们创建一个名为User
的隐藏参数,并将其作为第一个参数。对于其“可用值”属性,请创建如下所示的查询:
SELECT UserId, Name
FROM Users
WHERE UserId = @UserId OR @UserId = 'MyDomain\ReportingAccount'
其中MyDomain\ReportingAccount
是您的报告在其下运行的帐户。此查询仅在实际用户运行报表时允许特定用户详细信息,但在报表调度程序运行时允许所有用户。
将User
参数的默认值属性设为=User!UserId
。报表计划程序运行报表时,User
参数会为您要发送电子邮件的人提供所需的UserId。
因此,当用户运行报告时,它会选择唯一可能的用户(这是他们自己),并且当调度程序运行报告时,它会从所有可用用户中选择所需的用户。作为隐藏参数,用户永远不会看到它,因此不知道其中的差异。
如果用户试图通过将其作为参数传递给URL来智能并欺骗其他用户,则它将不是参数可用值的有效选择,因此将失败。
现在只需将上面用于公司选择的查询中的@UserId
替换为@User
,一切都应该有效。
答案 1 :(得分:0)
我会将安全实现向上推送到数据库,并强制通过筛选视图进行访问。通常的技术是构建一个表,列出每个用户可访问的公司,然后使用CURRENT_USER函数过滤具有该表的内部联接的视图。
这是一个更强大的解决方案,因为它不依赖于单个报告参数设置。它还将支持更多的部署方法,例如SharePoint,Web Apps,Excel等。
有了这个,您的Report Manager部署变得非常简单 - 您可以为所有用户提供对一组文件夹和报告的相同访问权限。