SSRS报表查看器+ ASP.NET凭证401异常

问题描述:

我有救了SQL2005报告服务器上的报告,我想回本报告渲染PDF。我已经与当地的* .rdlc文件时想通了这一点(,我已经博客上讲述它),而不是当*的.rdl驻留在报表服务器上。我在该行得到一个 401没有获得许可错误...

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

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

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


  • 这是Intranet上运行,并且启用了模拟。

  • 记录表明,模拟用户被正确设置。

  • 确实工作在Visual Studio中运行时(的http://本地主机:devport ),它的确实工作在我的开发机器上运行时(的http://本地主机/所有MyApplication )。它的无效在我们的测试或生产服务器上运行时。

  • 我曾尝试既没有在web.config中system.net.defaultProxy设置方案。但是都没有成功。

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

我是什么做错了吗?它是一个服务器设置?它是code?难道是web.config中?

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

我们也终于找出问题。我们的网络管理员已禁用双跳,因此而模仿被正确连接为域\\ jmeyer ,应用程序仍然试图用域\\ $ WEB01 。为什么设置这样的吗?由于双跳是一个巨大的安全漏洞。 (或者说,有人告诉我。这听起来像什么,你会读上每日跆拳道?)

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

我们的解决方案是创建一个通用的域\\ ssrs_report_services 用户,并与下面的网络凭据用户

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.