SQL SERVER 2008中,Reporting Service不再依赖于IIS,这带来很多利处,不过这也意味着不能够直接通过配置IIS的虚拟目录部署来实现匿名访问了。下面我们就看一下在SSRS 2008中怎么能够实现报表的“匿名访问”,不过对于一个正式项目来说,建议不要并且从不允许匿名来访问报表。
1. 实现IReportServerCredentials接口
对于使用Asp.Net的ReportViewer控件,实现IReportServerCredentials接口来实现自定义身份验证,然后通过设置成ReportView的属性ServerReport.ReportServerCredentials。此接口的定义:
view plaincopy to clipboardprint
- public interface IReportServerCredentials
- {
- WindowsIdentity ImpersonationUser { get; }
- ICredentials NetworkCredentials { get; }
- bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority);
- }
public interface IReportServerCredentials { WindowsIdentity ImpersonationUser { get; } ICredentials NetworkCredentials { get; } bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority); }
此接口定义了三种身份验证的方式来访问Report Server,可以单独使用,也可以组合使用这三种方式。
ImpersonationUser:ReportView在每次WebRequest请求到ReportServer前模拟的一个WindowsIdentity,实际上会调用这个属性的WindowsIdentity.Impersonate方法来完成。如果此属性返回null的话,则默认使用当前线程用户。
NetworkCredentials: 此属性的值将会经由WebRequest.Credentials属性直接传递给WebRequest,如果返回null的话,则默认是CredentialCache.DefaultCredentials,使用当前上下文的系统凭据,这也是通常我们使用的方式。
GetFormsCredentials:这是ReportServer特有的认证体系,如果返回true的话,输出参数将用来调用ReportServer上的LogonUser方法,这个方法是用来支持服务器上的安全扩展插件。
这个接口是如何被使用的呢,我们从report viewer说起。当ASPX page页面执行时,ReportView控件并不是一次性的请求ReportServer。这其间其实需要通过ReportViewer HTTP handler多次请求Report Server.就比如报表中显示一个图片,在客户端生成的html中有图片标签,对于其中的图片会请求ReportView控件,ReportView收到请求后会重新请求ReportServer索要这个图片,ReportServer这时还需要判断当前请求的用户是否和初始的用户一一致,如果一致才会返回图片。其它的例如ReportView提供的打印,导出也是同样的原理。
ReportView控件的IReportServerCredentials的实例的属性,存储在Asp.net SessionState中,这样即保证了安全性,又能够即时的获取到认证信息。不过这个接口提供的灵活性使我们在设置这个凭据时更加灵活,我们可以如下实现:
view plaincopy to clipboardprint
- [Serializable]
- class MyConfigFileCredentials : IReportServerCredentials
- {
- public MyConfigFileCredentials()
- {
- }
- public WindowsIdentity ImpersonationUser
- {
- get { return null; }
- }
- public ICredentials NetworkCredentials
- {
- get
- {
- return new NetworkCredential(
- ConfigurationManager.AppSettings["MyUserName"],
- ConfigurationManager.AppSettings["MyPassword"]);
- }
- }
- public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority)
- {
- authCookie = null;
- userName = null;
- password = null;
- authority = null;
- }
- }
[Serializable] class MyConfigFileCredentials : IReportServerCredentials { public MyConfigFileCredentials() { } public WindowsIdentity ImpersonationUser { get { return null; } } public ICredentials NetworkCredentials { get { return new NetworkCredential( ConfigurationManager.AppSettings["MyUserName"], ConfigurationManager.AppSettings["MyPassword"]); } } public bool GetFormsCredentials(out Cookie authCookie, out string userName, out string password, out string authority) { authCookie = null; userName = null; password = null; authority = null; } }
上面我们只提供第二种认证方式,创建一个NetwrokCredential实例,并且采用配置文件中存储的用户名和密码,可以在后期修改。在配置文件中创建两个参数的值为能够正常访问此报表的帐号和密码,然后给赋值给ReportView的属性即可:
view plaincopy to clipboardprint
- ReportViewer1.ServerReport.ReportServerCredentials = new MyConfigFileCredentials();
ReportViewer1.ServerReport.ReportServerCredentials = new MyConfigFileCredentials();
这样,当你浏览报表程序时,就不会提示输入用户名和密码了。或许你看到这里应该也意识到了,我们所说的匿名访问报表,并不是说报表设置给了everyone都可以访问,而是说我们包装了一下,省略了用户认证这一步,而模拟成了一个可以访问的用户,来实现的“匿名访问”。其实在先前使用IIS作为报表服务器的时候,也是通过在IIS中设置虚拟目录或者网站,来实现了这个模拟的动作。
2.实现IReportServerConnection接口
但是如果你的系统中禁止SessionState怎么办呢。这时你可以考虑实现IReportServerConnection 或者IReportServerConnection2 接口:
view plaincopy to clipboardprint
- public interface IReportServerConnection : IReportServerCredentials
- {
- Uri ReportServerUrl { get; }
- int Timeout { get; }
- }
- public interface class IReportServerConnection2 : IReportServerConnection, IReportServerCredentials
- {
- IEnumerable<Cookie> Cookies {get;}
- IEnumerable<string> Headers {get;}
- }
public interface IReportServerConnection : IReportServerCredentials { Uri ReportServerUrl { get; } int Timeout { get; } } public interface class IReportServerConnection2 : IReportServerConnection, IReportServerCredentials { IEnumerable<Cookie> Cookies {get;} IEnumerable<string> Headers {get;} }
从这两个接口的代码可以看出,他们的实例可以当做IReportServerCredentials来使用,所以上面介绍的方法对于他们们的实现同样管用。他们的属性值同样默认存储在SessionState中,当SessionState禁止时,我们要提供其它的访问方式,以下是我们的实现:
view plaincopy to clipboardprint
- [Serializable]
- public class MyReportServerConnection : IReportServerConnection2
- {
- public Uri ReportServerUrl
- {
- get
- {
- string url = ConfigurationManager.AppSettings["MyReportServerUrl"];
- if (string.IsNullOrEmpty(url))
- throw new Exception("Missing url from the Web.config file");
- return new Uri(url);
- }
- }
- public int Timeout
- {
- get { return 60000; }
- }
- public IEnumerable<Cookie> Cookies
- {
- get { return null; }
- }
- public IEnumerable<string> Headers
- {
- get { return null; }
- }
- public MyReportServerConnection()
- {
- }
- public WindowsIdentity ImpersonationUser
- {
- get { return null; }
- }
- public ICredentials NetworkCredentials
- {
- get
- {
- string userName = ConfigurationManager.AppSettings"[myReportViewerUser];
- if (string.IsNullOrEmpty(userName))
- throw new Exception("Missing user name from Web.config file");
- string password = ConfigurationManager.AppSettings["MyReportViewerPassword"];
- if (string.IsNullOrEmpty(password))
- throw new Exception("Missing password from Web.config file");
- string domain = ConfigurationManager.AppSettings["MyReportViewerDomain"];
- if (string.IsNullOrEmpty(domain))
- throw new Exception("Missing domain from Web.config file");
- return new NetworkCredential(userName, password, domain);
- }
- }
- public bool GetFormsCredentials(out Cookie authCookie,out string userName,out string password,out string authority)
- {
- authCookie = null;
- userName = null;
- password = null;
- authority = null;
- return false;
- }
- }
[Serializable] public class MyReportServerConnection : IReportServerConnection2 { public Uri ReportServerUrl { get { string url = ConfigurationManager.AppSettings["MyReportServerUrl"]; if (string.IsNullOrEmpty(url)) throw new Exception("Missing url from the Web.config file"); return new Uri(url); } } public int Timeout { get { return 60000; } } public IEnumerable<Cookie> Cookies { get { return null; } } public IEnumerable<string> Headers { get { return null; } } public MyReportServerConnection() { } public WindowsIdentity ImpersonationUser { get { return null; } } public ICredentials NetworkCredentials { get { string userName = ConfigurationManager.AppSettings"[myReportViewerUser]; if (string.IsNullOrEmpty(userName)) throw new Exception("Missing user name from Web.config file"); string password = ConfigurationManager.AppSettings["MyReportViewerPassword"]; if (string.IsNullOrEmpty(password)) throw new Exception("Missing password from Web.config file"); string domain = ConfigurationManager.AppSettings["MyReportViewerDomain"]; if (string.IsNullOrEmpty(domain)) throw new Exception("Missing domain from Web.config file"); return new NetworkCredential(userName, password, domain); } } public bool GetFormsCredentials(out Cookie authCookie,out string userName,out string password,out string authority) { authCookie = null; userName = null; password = null; authority = null; return false; } } }
要使HTTP handler在不存储的情况下还能够访问它,必须还要添加ReportView的WebConfig配置:
view plaincopy to clipboardprint
- <configuration>
- <appSettings>
- <add key="ReportViewerServerConnection" value="ReportsPortal.MyReportServerConnection,ReportsPortal"/>
- </appSettings>
- </configuration>
<configuration> <appSettings> <add key="ReportViewerServerConnection" value="ReportsPortal.MyReportServerConnection,ReportsPortal"/> </appSettings> </configuration>
同样的,我们直接赋值给ReportView的属性,就可以实现报表的“匿名访问”。
view plaincopy to clipboardprint
- this.ReportViewer1.ServerReport.ReportServerCredentials = new MyReportServerConnection();
this.ReportViewer1.ServerReport.ReportServerCredentials = new MyReportServerConnection();
参考和资源:
1.A Wrapper for Running SQL Server 2008 Reporting Services Reports Anonymously 调用ReportingService2005.asmx服务实现了一个匿名访问所有报表的管理器。
2.Custom Credentials in the Report Viewer 参考资源,有些为这个文章的译文
3.Anonymous access in SQL RS 2008 以另外一种方式来实现的匿名访问