在SSRS 2008报表管理器中获取用户/客户端查看报告的IP地址

时间:2012-10-25 20:30:31

标签: reporting-services ssrs-2008 ip-address

必须有办法做到这一点。我只需要一种方法来公开在SQL 2008(而不是r2)报表服务器上查看报表的用户的IP地址(或计算机名称 - 但我认为IP更容易获得)。这是我已经尝试过的:

  1. 在报告代码块中编写代码以获取IP地址,例如:

    Public Function GetClientIP() As String
        Dim sReturn As String = ""
        Dim ipHost As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName())
    
        For i As int32 = 0 To ipHost.AddressList.Length - 1
            If (Not ipHost.AddressList(i) Is Nothing AndAlso ipHost.AddressList(i).ToString().Trim() <> "" AndAlso ipHost.AddressList(i).ToString().Length() <= 15) Then
                sReturn = ipHost.AddressList(i).ToString()
            End If
        Next i
    
        Return sReturn
    End Function
    

    首先,这给了我各种安全权限错误,我可以通过在rssrvpolicy.config中将Report_Expressions_Default_Permissions的PermissionSet更改为FullTrust来解决它:

    <CodeGroup
      class="UnionCodeGroup"
      version="1"
      PermissionSetName="FullTrust"
      Name="Report_Expressions_Default_Permissions"
      Description="This code group grants default permissions for code in report expressions and Code element. ">
      <IMembershipCondition
      class="StrongNameMembershipCondition"
      version="1"
      PublicKeyBlob="0024000004800000940000000602000000240000525341310004000001000100512C8E872E28569E733BCB123794DAB55111A0570B3B3D4DE3794153DEA5EFB7C3FEA9F2D8236CFF320C4FD0EAD5F677880BF6C181F296C751C5F6E65B04D3834C02F792FEE0FE452915D44AFE74A0C27E0D8E4B8D04EC52A8E281E01FF47E7D694E6C7275A09AFCBFD8CC82705A06B20FD6EF61EBBA6873E29C8C0F2CAEDDA2"
      />
    </CodeGroup>
    

    毕竟我发现它正在返回服务器IP地址而不是客户端!这不是thisthis所说的。

  2. 我尝试了不同的ASP.net变量,例如HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]

    1. 仅在部署时有效,并在从调试器运行时抛出错误(我想这是预期的)和
    2. 它还仅返回服务器IP地址!
    3. 实际上我写了一个快速脚本来获取所有服务器变量并在报告屏幕上显示它,但它们都不包含客户端IP地址!

      Public Function GetServerVariables() AS String
          Dim sReturn as String = ""
      
          for i as int32 = 0 to System.Web.HttpContext.Current.Request.ServerVariables.Count -1
              sReturn &=System.Web.HttpContext.Current.Request.ServerVariables.Keys(i).ToString & ": " & System.Web.HttpContext.Current.Request.ServerVariables.Item(i).ToString() & " - "
          next i
      
          Return sReturn
      End Function
      
    4. 我尝试在vb.NET中创建一个自定义程序集,它基本上运行与上面的GetClientIP()函数完全相同的代码,但是经过几天的尝试后我无法解决该问题的权限错误。我最终放弃了这个,因为大约在同一时间我得到了步骤(1)的报告代码,并且由于它返回了服务器IP地址,我认为自定义程序集将返回相同的东西。

    5. 所以我们拥有它。对于冗长的解释感到抱歉,但我希望尽可能彻底。对于那些想知道我为什么需要用户IP地址的人来说,这实际上是另一个复杂的故事,如果有人真的想知道,我会在另一篇文章中解释它。

      最重要的是,我需要在浏览器中运行报告的计算机的IP地址或计算机名称。用户名或任何其他详细信息是不够的,除非它们可用于以某种方式查找IP地址。

4 个答案:

答案 0 :(得分:1)

我花了一些时间试图返回客户端IP并且也没有成功。但是,我想我会告诉你我做了什么,以防它向你提出更进一步的建议,或者你的环境与我的环境有什么不同。我正在SharePoint集成模式下运行。

首先,我以为我会通过传递IP作为参数绕过服务器,所以我将以下函数编写为自定义代码:

Public Function GetIPAddress() As String
    Dim strHostName As String
    Dim strIPAddress As String
    strHostName = System.Net.Dns.GetHostName()
    strIPAddress = System.Net.Dns.GetHostByName(strHostName).AddressList(0).ToString()

    Return strIPAddress
End Function

然后我有一个带有表达式的参数:

=Code.GetIPAddress()

很好的理论,并在本地工作得很漂亮,但在部署时,自定义代码在服务器上得到评估,我得到了我的Reporting Services服务器IP地址,而不是本地的。

然后我用各种变量尝试了HttpContext,这样做有点好,但不是很多:

Public Function GetClientIP() As String
    Dim IpAddress As String

    IpAddress = "UserHost: " + System.Web.HttpContext.Current.Request.UserHostAddress + " ClientIP: " + System.Web.HttpContext.Current.Request.ServerVariables("HTTP_CLIENT_IP") + " Remote: " + System.Web.HttpContext.Current.Request.ServerVariables("REMOTE_ADDR") +         " Forward: " + System.Web.HttpContext.Current.Request.ServerVariables("HTTP_X_FORWARDED_FOR")
   return IpAddress
End Function

UserHostAddress为我提供了SharePoint服务器IP,HTTP_CLIENT_IP为空,REMOTE_ADDR为SharePoint服务器IP,HTTP_X_FORWARDED_FOR为空。

所以可能无法完成。在任何情况下,都有some reasons to avoid using HttpContext in reports,包括它在异步线程(用于呈现报告)中不可用,也不在未使用Http请求执行的报告订阅中。

无论如何,这就是我应对的地方 - 祝你好运!

答案 1 :(得分:1)

您需要为您的程序集提供强名称和fulltrust权限。

在每次调用.net服务之前,您必须断言所需的权限,并在通话后立即将其重新置位。

您在rssrvpolicy.config文件中授予您的程序集权限 在管理工具中,.net配置工具用于管理代码组和权限。 我建议为自定义程序集添加新的代码组和权限。

要使用您的更新,您必须停止并重新启动报告服务。

要报告服务以使用自定义程序集,它需要您的自定义程序集 fulltrust。一旦您拥有所有权限,您将收到错误消息 程序集不允许部分信任的调用者。

要解决此问题,请编辑assemblyinfo.vb文件并添加以下代码行:

程序集:AllowPartiallyTrustedCallers()

使用&lt; ...&gt;封装上面的代码,因为编辑器保留了我删除它们 删除整行。

修复权限后,可以使用.net配置工具将自定义程序集添加到程序集缓存中。请注意,每次更改装配时,您都会这样做 需要将.dll文件复制到您决定使用的目录。从中取出组件 缓存并重新添加它。否则,您将始终调用旧版本的程序集 当您在报表项目中时,导航到报表然后引用。你的装配将是 在可用程序集的.n​​et列表中列出。

另外,请务必小心对Report_Expressions_Default_Permissions所做的更改。给予 ittrust会为您的服务器上运行的所有代码提供无论是您的还是黑客完全访问任何报表中的任何表达式的完全访问权限和访问权限。

请记住,rssrvpolicy.config中的更改应该针对报表管理器的rsmgrpolicy.config进行。

为自定义程序集提供所需的权限更安全 代码看起来类似于:

    Dim SecurityPermission As New PermissionSet(PermissionState.Unrestricted)
    Try
        Dim SqlClientPermission As New SqlClientPermission(PermissionState.Unrestricted)

        SqlClientPermission.Assert()

        If pSqlCmd() <> vbNullString Then
            cmd = New System.Data.SqlClient.SqlCommand(pSqlCmd(), con)
        Else
            cmd = New System.Data.SqlClient.SqlCommand(sql, con)
        End If

    Catch ex As System.Data.SqlClient.SqlException
        SqlClientPermission.RevertAssert()
        SecurityPermission.Assert()
        Authorized = False
        pErrorMsg(ex.ToString())
    Catch ex As System.Security.SecurityException
        SqlClientPermission.RevertAssert()
        SecurityPermission.Assert()
        Authorized = False
        pErrorMsg(ex.ToString())
    Catch ex As Exception
        SqlClientPermission.RevertAssert()
        SecurityPermission.Assert()
        Authorized = False
        pErrorMsg(ex.ToString())
    Finally
        SqlClientPermission.RevertAssert()

    End Try

    The above code does not need SecurityPermission.   I am asserting it because the 
    exception handler assumes I do not have full access to the security system.  
    Its assumption means it gives me less information in the exception message.   By
    asserting SecurityPermission before accessing the exception message, I am able to 
    attain a full explaination of the error.   

    Note as well, that you are only allowed to make one permission assertion at a time.
    There are other methods available to add permissions to a permissionset and then
    assert that permission set.  That is why you see in the above code a RevertAssert
    to remove the current assertion before asserting another. 

   (*** There is no RevertAssert for SecurityPermission.Assert because its reverted when the 
        current routine ends ***)

    When I have time, I will write some documentation on this process.  I painfully worked 
    my way through it.  

答案 2 :(得分:1)

我希望有人能够在运行报告时为我提供一个更简单的解决方案来查找用户的IP地址,但这里有 工作解决方案,我可以在几周内一起攻击。

首先,我对自定义程序集或报表代码块没有好运,因为我得到的只是服务器IP地址而不是客户端。相反,我决定在报告管理器aspx页面中使用jquery来完成这项肮脏的工作。

以下是我可以直截了当的步骤:

1)在Program Files \ Microsoft SQL Server报告服务器\ MSRS10.Instancename \ Reporting Services \ ReportManager \ Pages目录中创建一个名为GetClientIPAddress.aspx的新文件。 GetClientIPAddress.aspx的内容如下所示:

<%=Request.ServerVariables["REMOTE_ADDR"]%>

这是实际获取客户端IP地址的页面。

2)编辑同一文件夹中的Folder.aspx文件,并在文件底部添加此javascript代码:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript">
$(document.body).ready(function () {
    try {
        var sReportName = 'Name of report here'

        $("a").each(function() {
            if (this.innerText == sReportName  || this.textContent == sReportName)
            {
                this.href = this.href.replace('Report.aspx','ReportEx.aspx');
            }
        });
    }
    catch (e) { }
});
</script>

将“报告名称”替换为报告名称。报告名称默认为报告的文件名减去扩展名。您可以在报告“属性”标签中找到并更改此值&gt; “常规”子标签&gt; “名称”字段。

3)最后,在名为ReportEx.aspx的同一文件夹中创建一个新文件。此文件基于并使用与Report.aspx文件相同的标头:

<%@ Register TagPrefix="MSRS" Namespace="Microsoft.ReportingServices.UI" Assembly="ReportingServicesWebUserInterface" %>
<%@ Page language="c#" Codebehind="Report.aspx.cs" AutoEventWireup="false" Inherits="Microsoft.ReportingServices.UI.ReportWrapperPage" EnableEventValidation="false" %>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript">
function getUrlVars()
{
    var vars = [], hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
    return vars;
}

$(document.body).ready(function () {
    try {
        var sItemPath = getUrlVars()["ItemPath"];
        var sSelectedTab = getUrlVars()["SelectedTabId"];

        if (sSelectedTab === undefined || sSelectedTab == 'ViewTab')
        {
            $("table.msrs-normal").each(function() {
                if (this.rows.length == 2 && this.rows[0].cells.length == 1)
                {
                    var sIPAddress = $.ajax({
                        type: "GET",
                        url: 'GetClientIPAddress.aspx',
                        async: false
                    }).responseText;

                    this.rows[1].cells[0].innerHTML = '<iframe style="width: 100%; height: 100%;" frameborder="0" src="http://servername/ReportServer/Pages/ReportViewer.aspx?'+sItemPath+'&rs:Command=Render&IPAddress='+sIPAddress+'"></iframe>';
                }
            });
        }
    }
    catch (e) { }
});
</script>

将'servername'替换为运行report / sql server的服务器的IP地址或计算机名称。

这种“黑客攻击”的工作原理是有效地拦截你的报告的锚标记href链接,并用一个几乎相同的链接替换它,该链接转到ReportEx.aspx而不是Report.aspx。在ReportEx页面上,对GetClientIPAddress.aspx页面进行ajax javascript调用,该页面返回客户端IP地址。该报告通过javascript有效隐藏或删除,并替换为完全相同报告的iframe。唯一的区别是新报告将ip地址设置为查询字符串参数,这次参数直接传递给报告。这当然要求您在报告中创建一个名为“IPAddress”的参数,以便在我们完成所有这些工作后才能正确接受它!

所以我们拥有它。如果有人能想出更好的方法来做到这一点,或者甚至是简化一些步骤的方法,我很乐意听到它!这是在SQL Server 2008上完成的,我想这个解决方案可以在更早版本和更新版本上运行,但可能会稍微改变代码。作为这个解决方案的回合,我提供它是希望其他人可以从我花费的时间和时间中获益,试图找出 A 方式, ANY 方式这!

答案 3 :(得分:-1)

另一种选择: 启用Report Server HTTP Log

要配置报表服务器HTTP日志,请使用记事本修改ReportingServicesService.exe.config文件。配置文件位于\ Program Files \ Microsoft SQL Server \ MSSQL.n \ Reporting Services \ ReportServer \ Bin文件夹中。 要启用HTTP服务器,必须将http:4添加到ReportingServicesService.exe.config文件的RStrace部分。所有其他HTTP日志文件条目都是可选的。以下示例包含所有设置,以便您可以将整个部分粘贴到RStrace部分,然后删除不需要的设置。

   <RStrace>
     <add name="FileName" value="ReportServerService_" />
     <add name="FileSizeLimitMb" value="32" />
     <add name="KeepFilesForDays" value="14" />
     <add name="Prefix" value="tid, time" />
     <add name="TraceListeners" value="debugwindow, file" />
     <add name="TraceFileMode" value="unique" />
     <add name="HttpTraceFileName" value="ReportServerService_HTTP_" />
     <add name="HttpTraceSwitches" value="date,time,clientip,username,serverip,serverport,host,method,uristem,uriquery,protocolstatus,bytesreceived,timetaken,protocolversion,useragent,cookiereceived,cookiesent,referrer" />
     <add name="Components" value="all:3,http:4" />
   </RStrace>

field ClientIp - 访问报表服务器的客户端的IP地址。请注意,HttpTraceSwitches中的逗号后面必须没有空格(否则SSRS会默默忽略它)。