问题
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:
- You need to do this in code behind in my experience.
- You want a 'ReportViewer' object.
- 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