Credenciais SSRS Report Viewer + ASP.NET 401 de exceção
-
10-07-2019 - |
Pergunta
Eu tenho um relatório salvo em um servidor de relatórios SQL2005, e quero retornar um PDF processado deste relatório. Eu descobri isso quando se trabalha com um arquivo .rdlc * local ( e eu tenho um blog sobre isso ), mas não quando reside * .rdl em um servidor de relatórios. Estou recebendo um 401 Não autorizado Erro na linha ...
reportViewer.ServerReport.SetParameters(reportDefinition.ReportParameters);
Aqui está o método utilizado para processar o relatório.
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;
}
A outra coisa que está faltando é a classe 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);
}
}
Outras coisas que você pode precisar de saber ...
- Este está sendo executado em uma intranet, e a representação estiver activada.
- Registro indica que o usuário representação está sendo definido corretamente.
- Este funciona quando executado no Visual Studio (
http://localhost:devport
), e funciona quando em execução no meu caixa de desenvolvimento (http://localhost/myApplication
). É não funciona quando executado em nossos servidores de teste ou de produção. - Eu tentei soluções com e sem configurações system.net.defaultProxy em web.config. Nem funcionou.
O que estou fazendo de errado? É uma configuração do servidor? É código? É web.config?
Solução
Nós fez finalmente descobrir o problema. Nossos administradores de rede têm desativado double-hopping, por isso, enquanto a representação foi corretamente conectando como domain\jmeyer
, o aplicativo ainda estava tentando se conectar à caixa de SRS com domain\web01$
. Por que é configurado como este? Porque double-hopping é uma falha de segurança enorme. (Ou assim me foi dito. Isso soa como algo que você leria sobre The Daily WTF ?)
A nossa solução foi criar um usuário domain\ssrs_report_services
genérico, e se conectar com o usuário com as seguintes credenciais de rede
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") ; }
}
}
A descrição acima é o exemplo solução clássica que você pode encontrar tudo sobre os internets.
Outras dicas
"Double pulando" é permitido - (! Contanto que ele está funcionando corretamente) swith a autenticação Kerberos ...