3

必须有办法做到这一点。我只需要一种方法来公开在 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 地址而不是客户端!这不是这个这个说的。

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

    1. 仅在部署时有效,并在从调试器运行时抛出错误(我想这是意料之中的)和
    2. 它还只返回服务器 IP 地址!

    事实上,我编写了一个快速脚本来获取所有服务器变量并将其显示在报告屏幕上,但其中没有一个包含客户端 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
    
  3. 我尝试在 vb.NET 中创建一个自定义程序集,该程序集基本上运行与上面的 GetClientIP() 函数完全相同的代码,但经过几天的尝试后,我无法使用该函数解决权限错误。我最终放弃了这一点,因为大约在同一时间,我从步骤 (1) 中获得了报告代码,并且由于它正在返回服务器 IP 地址,因此我认为自定义程序集将返回相同的内容。

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

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

4

4 回答 4

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 地址,而不是我的本地 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 为空白。

所以它可能无法完成。在任何情况下,有一些原因可以避免在报告中使用 HttpContext,包括它在异步线程(用于呈现报告)中以及在不使用 Http 请求执行的报告订阅中不可用。

无论如何,这就是我要解决的问题 - 祝你好运!

于 2012-10-26T05:16:15.363 回答
1

您需要为您的程序集提供强名称和完全信任权限。

在每次调用 .net 服务之前,您必须声明所需的权限并在调用后立即恢复它。

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

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

要使报告服务使用您的自定义程序集,它要求您的自定义程序集具有完全信任。一旦您设置了所有权限,您将收到错误消息,即程序集不允许部分受信任的调用者。

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

程序集:AllowPartiallyTrustedCallers()

用 <...> 封装上面的代码,我删除它们是因为编辑器一直删除整行。

修复权限后,您可以使用 .net 配置工具将自定义程序集添加到程序集缓存中。请注意,每次对程序集进行更改时,都需要将 .dll 文件复制到您决定使用的目录中。从缓存中删除程序集并重新添加它。否则,您将始终调用旧版本的程序集。
当您在报表项目中时,导航到报表然后参考。您的程序集将列在可用程序集的 .net 列表中。

此外,对您对 Report_Expressions_Default_Permissions 所做的更改要非常小心。给予它完全信任可以让在你的服务器上运行的所有代码,无论是你的还是黑客的,都可以在任何报告中以任何表达式完全访问完全信任和访问。

请记住,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.  
于 2012-11-02T14:04:59.197 回答
1

我希望有人在运行报告时给我一个更简单的解决方案来查找用户的 IP 地址,但这是一个可行的解决方案,我能够在几周内一起破解。

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

以下是我可以说的最简单的步骤:

1) 在 Program Files\Microsoft SQL Server Reporting 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>

将“此处的报告名称”替换为您的报告名称。默认情况下,报告名称是报告的文件名减去扩展名。您可以在报告“属性”选项卡 >“常规”子选项卡 >“名称”字段中找到并更改此值。

3) 最后,在同一文件夹中创建一个名为 ReportEx.aspx 的新文件。此文件基于 Report.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”替换为运行报告/sql 服务器的服务器的 IP 地址或计算机名称。

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

因此,我们有它。如果有人能想到更好的方法来做到这一点,或者甚至是简化我的一些步骤的方法,我很想听听!这是在 SQL Server 2008 上完成的,我想这个解决方案可以在较早和较新的版本上工作,但可能对代码稍作改动。尽管这个解决方案是迂回的,但我提供它是希望其他人可以从我花费数小时试图找出一种方法,任何方法来做到这一点中受益!

于 2012-11-08T17:54:14.160 回答
-1

另一个选项:启用报表服务器 HTTP 日志

要配置报表服务器 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>

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

于 2014-10-20T04:59:01.200 回答