SQL Server 2008 Reporting Services實現匿名訪問報表

iSQlServer發表於2010-01-11
   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 Cookies {get;}   
    IEnumerable Headers {get;}   


public interface IReportServerConnection : IReportServerCredentials
{
    Uri ReportServerUrl { get; }
    int Timeout { get; }
}
public interface class IReportServerConnection2 : IReportServerConnection, IReportServerCredentials
{
    IEnumerable Cookies {get;}
    IEnumerable 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 Cookies   
      {   
          get { return null; }   
      }   
      public IEnumerable 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 Cookies
        {
            get { return null; }
        }
        public IEnumerable 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
   
       
           
   
   
 


   
       
   


         同樣的,我們直接賦值給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   以另外一種方式來實現的匿名訪問

作者:孤獨俠客(似水流年)
出處:http://lonely7345.cnblogs.com/

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-624805/,如需轉載,請註明出處,否則將追究法律責任。

相關文章