如何在报告服务中实现用户模拟

本文关键字:实现 用户 模拟 服务 报告 | 更新日期: 2023-09-27 18:31:03

这个问题涉及的软件是:

  • SQL Server Reporting Services 2008 R2
  • SQL Server Analysis Services 2008 R2
  • SQL Server 2008 R2 数据库引擎
  • ASP.NET 4.5 网页表单
  • 报表查看器组件

我们有几十份报告。有些报表对数据仓库数据库使用 T-SQL 查询,有些报表对 SSAS 多维数据集使用 MDX 查询。

Active Directory 安全组保护用户可以在报表服务器上访问的报表。

我们还制作了具有维度权限的 SSAS 角色,这些角色可以有效地保护每个用户可以访问的数据。我们使用 AMO 代码来生成和维护这些角色和成员身份,因为有多少,但这无关紧要,与问题无关。

我知道 SSAS 有一个称为有效用户名的功能,我们可以将其传递给多维数据集进行模拟。

但是,我们如何在 SSRS 中模拟用户,以便我们只能看到该用户有权访问的报表?

我们目前正在尝试使用 ASP.NET 并使用ReportViewer组件制定自定义报表管理器的软件设计。我们希望向管理员公开一个文本框或下拉列表,允许他们输入或选择员工并以该员工的身份有效运行。

换句话说,即使我以 DOMAIN''User1 身份在 ASP.NET 报表管理器站点中进行身份验证,如果我在报表服务器上以管理员身份担任某种角色,我也希望能够在文本框中键入用户名(如 User2),并能够像 DOMAIN''User2 看到它们一样查看报表服务器上的所有报表。

感谢您提供的任何建议或答案。

如何在报告服务中实现用户模拟

几件事:

  1. 根据我的经验,您需要在代码后面执行此操作。
  2. 您需要一个"报表查看器"对象。
  3. 我相信如果你是托管,你需要一个参考'Microsoft.ReportViewer.WinForms' dll。

我使用的代码是使用 xaml 完成的,用于托管报表查看器的 WPF(删节):

< Window x:Class="WPFTester.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:rv="clr-namespace:Microsoft.Reporting.WinForms;assembly=Microsoft.ReportViewer.WinForms"
    >
  ......
<WindowsFormsHost Grid.Row="2">
        <rv:ReportViewer x:Name="reportViewer"></rv:ReportViewer>
    </WindowsFormsHost>
......
</Window>

你得到的重要部分是我有一个名为"reportViewer"的"ReportViewer"对象用于我的代码隐藏。 ASP.NET 具有此对象的等效项,但您还需要别名"rv"或类似名称中的 dll。 代码的工作方式类似于这样:

private void ResetReportViewer(ProcessingMode mode)
        {
            this.reportViewer.Clear();
            this.reportViewer.LocalReport.DataSources.Clear();
            this.reportViewer.ProcessingMode = mode;
        }

        private void ReportViewerRemoteWithCred_Load(object sender, EventArgs e)
        {
            ResetReportViewer(ProcessingMode.Remote);
            reportViewer.ServerReport.ReportServerUrl = new Uri(@"(http://myservername/ReportServer");
            reportViewer.ServerReport.ReportPath = "/Test/ComboTest";
            DataSourceCredentials dsCrendtials = new DataSourceCredentials();
            dsCrendtials.Name = "DataSource1";  // default is this you may have different name
            dsCrendtials.UserId = "MyUser";  // Set this to be a textbox
            dsCrendtials.Password = "MyPassword";  // Set this to be a textbox
            reportViewer.ServerReport.SetDataSourceCredentials(new DataSourceCredentials[] { dsCrendtials });
            reportViewer.RefreshReport();
        }

我从未使用过您提到的服务,但我希望以下东西会以某种方式对您有所帮助。

我使用 kernal32.dll 和 advapi32.dll 来模拟用户,如下所示:

Imports System.Security.Principal
Imports System.Runtime.InteropServices
Public Class UserImpersonation
<DllImport("advapi32.dll")> _
Public Shared Function LogonUserA(ByVal lpszUserName As [String], ByVal lpszDomain As [String], ByVal lpszPassword As [String], ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function DuplicateToken(ByVal hToken As IntPtr, ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
End Function
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function RevertToSelf() As Boolean
End Function
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function CloseHandle(ByVal handle As IntPtr) As Boolean
End Function
Public Const LOGON32_LOGON_INTERACTIVE As Integer = 2
Public Const LOGON32_PROVIDER_DEFAULT As Integer = 0
Private impersonationContext As WindowsImpersonationContext
Private Const UserName As String = "USER_ID"
Private Const Password As String = "USER_DOMAIN_PASSWORD"
Private Const Domain As String = "USER_DOMAIN_NAME"
Public Function ImpersonateValidUser() As Boolean
    Dim tempWindowsIdentity As WindowsIdentity
    Dim token As IntPtr = IntPtr.Zero
    Dim tokenDuplicate As IntPtr = IntPtr.Zero
    If RevertToSelf() Then
        If LogonUserA(UserName, Domain, Password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
            If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                impersonationContext = tempWindowsIdentity.Impersonate()
                If impersonationContext IsNot Nothing Then
                    CloseHandle(token)
                    CloseHandle(tokenDuplicate)
                    Return True
                End If
            End If
        End If
    End If
    If token <> IntPtr.Zero Then
        CloseHandle(token)
    End If
    If tokenDuplicate <> IntPtr.Zero Then
        CloseHandle(tokenDuplicate)
    End If
    Return False
End Function
Public Sub UndoImpersonation()
    If impersonationContext IsNot Nothing Then
        impersonationContext.Undo()
    End If
End Sub
End Class

现在,在代码中的适当位置使用它,例如:

Public SomeOtherClass
Public Function ReadFile() As CalFileInfo
    Try
        Dim objImpersonation As New UserImpersonation()
        If (objImpersonation.ImpersonateValidUser()) Then
            'Do necessary stuff....
            objImpersonation.UndoImpersonation()
        Else
            objImpersonation.UndoImpersonation()
            Throw New Exception("User do not has enough permissions to perform the task")
        End If
    Catch ex As Exception
        ''MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    End Try
    Return CalFileInformation
End Function
End Class