How to implement user impersonation in reporting services?

旧巷老猫 提交于 2019-12-13 04:35:44

问题


Software involved in this question is:

  • SQL Server Reporting Services 2008 R2
  • SQL Server Analysis Services 2008 R2
  • SQL Server 2008 R2 Database Engine
  • ASP.NET 4.5 Web Forms
  • ReportViewer component

We have several dozen reports. Some reports use T-SQL queries to our Data Warehouse database and some use MDX queries to our SSAS Cube.

Active Directory Security Groups secure which reports a user can access on the Report Server.

We additionally have made SSAS Roles that have Dimension Permissions on them which effective secures which data each user can access. We used AMO code to generate and maintain these roles and membership due to how many there are but that is beside the point and unrelated to the question.

I understand that there is a feature of SSAS called EffectiveUserName that we can pass to the cube for impersonation.

However, how can we impersonate a user within SSRS such that we will see only the reports that that user has access to?

We are currently trying to work out the software design of a custom report manager with ASP.NET and using the ReportViewer component. We would like to expose a text box or drop down to Administrators that allows them to put in or select employees and effectively run as that employee.

So in other words, even though I am authenticated into the ASP.NET Report Manager site as DOMAIN\User1, if I am in some role on the report server as an Administrator, I want to be able to type into a text box a username like User2 and be able to view all reports on the report server as DOMAIN\User2 would see them.

Thanks for any advice or answers you can offer.


回答1:


A few things:

  1. You need to do this in code behind in my experience.
  2. You want a 'ReportViewer' object.
  3. I believe if you are hosting you need a reference to 'Microsoft.ReportViewer.WinForms' dll.

The code I used was done with xaml for WPF hosting a ReportViewer (abridged):

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

The important part you get is that I have a 'ReportViewer' Object named 'reportViewer' for my code behind. ASP.NET has some equivalent of this object but you also will also need the dll in the alias of 'rv' or similar. The code works similar to this:

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();
        }



回答2:


I never worked with services you have mentioned but I hope, following stuff will help you in some way.

I used kernal32.dll and advapi32.dll to impersonate user as under:

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

Now, consume it at appropriate place in your code like:

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


来源:https://stackoverflow.com/questions/18772349/how-to-implement-user-impersonation-in-reporting-services

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!