SSRS 报告查看器 + ASP.NET 凭据 401 异常

发布于 2024-08-04 23:15:38 字数 2675 浏览 5 评论 0原文

我在 SQL2005 报告服务器上保存了一份报告,我想返回该报告的渲染 PDF。我在使用本地 *.rdlc 文件时发现了这一点(并且我已在博客中介绍过它),但当 *.rdl 驻留在报告服务器上时则不然。我在线路中收到 401 Not Authorized 错误...

reportViewer.ServerReport.SetParameters(reportDefinition.ReportParameters);

这是用于呈现报告的方法。

public byte[] Render(IReportDefinition reportDefinition)
{
    var reportViewer = new ReportViewer();
    byte[] renderedReport;
    try
    {
        var credentials = new WindowsImpersonationCredentials();
        reportViewer.ServerReport.ReportServerUrl = new Uri("http://myssrsbox", UrlKind.Absolute);
        reportViewer.ServerReport.ReportServerCredentials = credentials;
        reportViewer.ServerReport.ReportPath = reportDefinition.Path;
        // Exception is thrown on the following line...
        reportViewer.ServerReport.SetParameters(reportDefinition.ReportParameters);

        string mimeType;
        string encoding;
        string filenameExtension;
        string[] streams;
        Warning[] warnings;

        renderedReport = reportViewer.ServerReport.Render(reportDefinition.OutputType, reportDefinition.DeviceInfo, out mimeType, out encoding, out filenameExtension, out streams, out warnings);
    }
    catch (Exception ex)
    {
        // log the error...
        throw;
    }
    finally
    {
        reportViewer.Dispose();
    }
    return renderedReport;
}

您缺少的另一件事是 WindowsImpersonationCredentials 类。

public class WindowsImpersonationCredentials : IReportServerCredentials
{
    public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
    {
        authCookie = null;
        userName = password = authority = null;
        return false;
    }

    public WindowsIdentity ImpersonationUser
    {
        get { return WindowsIdentity.GetCurrent(); }
    }

    public ICredentials NetworkCredentials
    {
        get { return null; }
    }

    public override string ToString()
    {
        return String.Format("WindowsIdentity: {0} ({1})", this.ImpersonationUser.Name, this.ImpersonationUser.User.Value);
    }
}

您可能需要了解的其他事项...

  • 这是在 Intranet 上运行,并且模拟已打开。
  • 日志记录表明模拟用户设置正确。
  • 在 Visual Studio (http://localhost:devport) 中运行时有效,在我的开发盒上运行时有效 ( http://localhost/myApplication)。在我们的测试或生产服务器上运行时它不起作用
  • 我尝试过在 web.config 中使用和不使用 system.net.defaultProxy 设置的解决方案。两者都不起作用。

我做错了什么?是服务器设置吗?是代码吗?是 web.config 吗?

I have a report saved on a SQL2005 reporting server, and I want to return a rendered PDF of this report. I've figured this out when working with a local *.rdlc file (and I've blogged about it), but not when the *.rdl resides on a reporting server. I am getting a 401 Not Authorized error at the line...

reportViewer.ServerReport.SetParameters(reportDefinition.ReportParameters);

Here's the method used to render the report.

public byte[] Render(IReportDefinition reportDefinition)
{
    var reportViewer = new ReportViewer();
    byte[] renderedReport;
    try
    {
        var credentials = new WindowsImpersonationCredentials();
        reportViewer.ServerReport.ReportServerUrl = new Uri("http://myssrsbox", UrlKind.Absolute);
        reportViewer.ServerReport.ReportServerCredentials = credentials;
        reportViewer.ServerReport.ReportPath = reportDefinition.Path;
        // Exception is thrown on the following line...
        reportViewer.ServerReport.SetParameters(reportDefinition.ReportParameters);

        string mimeType;
        string encoding;
        string filenameExtension;
        string[] streams;
        Warning[] warnings;

        renderedReport = reportViewer.ServerReport.Render(reportDefinition.OutputType, reportDefinition.DeviceInfo, out mimeType, out encoding, out filenameExtension, out streams, out warnings);
    }
    catch (Exception ex)
    {
        // log the error...
        throw;
    }
    finally
    {
        reportViewer.Dispose();
    }
    return renderedReport;
}

The other thing that you're missing is the WindowsImpersonationCredentials class.

public class WindowsImpersonationCredentials : IReportServerCredentials
{
    public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
    {
        authCookie = null;
        userName = password = authority = null;
        return false;
    }

    public WindowsIdentity ImpersonationUser
    {
        get { return WindowsIdentity.GetCurrent(); }
    }

    public ICredentials NetworkCredentials
    {
        get { return null; }
    }

    public override string ToString()
    {
        return String.Format("WindowsIdentity: {0} ({1})", this.ImpersonationUser.Name, this.ImpersonationUser.User.Value);
    }
}

Other things you may need to know...

  • This is running on an intranet, and impersonation is turned on.
  • Logging indicates that the impersonation user is being set correctly.
  • This does work when running in Visual Studio (http://localhost:devport), and it does work when running on my development box (http://localhost/myApplication). It does not work when running on our test or production servers.
  • I have tried solutions both with and without system.net.defaultProxy settings in web.config. Neither worked.

What am I doing wrong? Is it a server setting? Is it code? Is it web.config?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

说不完的你爱 2024-08-11 23:15:38

我们终于弄清楚了问题所在。我们的网络管理员已禁用双跳,因此虽然模拟已正确连接为 domain\jmeyer,但应用程序仍在尝试使用 domain\web01$ 连接到 SRS 框>。为什么要这样设置呢?因为双跳是一个巨大的安全漏洞。 (至少有人告诉我。这听起来像您在 The Daily WTF 上读到的东西吗?)

我们的解决方案是创建通用 domain\ssrs_report_services 用户,并使用以下网络凭据与该用户连接

public class CustomCredentials : IReportServerCredentials
{
    public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
    {
        authCookie = null;
        userName = password = authority = null;
        return false;
    }

    public WindowsIdentity ImpersonationUser
    {
        get { return null; }
    }

    public ICredentials NetworkCredentials
    {
        get { return new NetworkCredential("ssrs_report_services", "password", "domain") ; }
    }    
}

以上是您可以在 Internet 上找到的经典示例解决方案。

We did finally figure out the problem. Our network administrators have disabled double-hopping, so while the impersonation was correctly connecting as domain\jmeyer, the application was still attempting to connect to the SRS box with domain\web01$. Why is it set up like this? Because double-hopping is a massive security hole. (Or so I was told. Does this sound like something you would read on The Daily WTF?)

Our solution was to create a generic domain\ssrs_report_services user, and connect with that user with the following network credentials

public class CustomCredentials : IReportServerCredentials
{
    public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
    {
        authCookie = null;
        userName = password = authority = null;
        return false;
    }

    public WindowsIdentity ImpersonationUser
    {
        get { return null; }
    }

    public ICredentials NetworkCredentials
    {
        get { return new NetworkCredential("ssrs_report_services", "password", "domain") ; }
    }    
}

The above is the classic example solution that you can find all over the internets.

赏烟花じ飞满天 2024-08-11 23:15:38

允许“双跳” - 切换 Kerberos 身份验证...(只要它正常工作!)

"Double hopping" is allowed - swith on Kerberos authentication ... (so long as it is working properly!)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文