利用集成 windows身份驗證在 IIS中承載此服務,以保護服務器

錯誤信息: 利用集成 windows身份驗證在 IIS中承載此服務,以保護服務器

錯誤原因:ChannelServices.RegisterChannel(new HttpChannel(9999),true); 使用了HttpChannel ,並且註冊時用了 ensureSecurity=True

詳細原因:轉載 http://blog.csdn.net/blue_sky_blue_heart/article/details/1130914


在進行Remoting開發過程中,一種流行的做法是將諸如對象激活方式,註冊通道的類型,端口信息等寫在配置文件中,然後使用RemotingConfiguration.Configure (String)方法讀取這些信息並完成遠程調用的配置。此時你會發現,.NET編譯器提示該方法已經過期,推薦使用RemotingConfiguration.Configure (String, Boolean),這是.NET FrameWork2.0版中新增的方法。後者與前者的區別僅在於多了一個參數,完整的表示形式爲:
public static void Configure ( string filename, bool ensureSecurity )
那麼後面的這個ensureSecurity布爾型參數究竟有什麼用呢。Msdn上給出的解釋非常簡單,如下:
ensureSecurity
如果啓用安全性,則爲 true;否則爲 false。
顯然不滿足安全性要求會拋出一個SecurityException異常來,但是如何啓用安全性,處理針對誰的安全性都沒有詳細的說明。在Google上搜索了一下,發現大家還熱衷於使用那個過時的版本,很少有用public static void Configure ( string filename, bool ensureSecurity )這種形式的,至於相關說明就更是少之又少。下面是用.Net Reflecter工具看到的Configure ( string filename, bool ensureSecurity )內部實現代碼:

        

[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
public static void Configure(string filename, bool ensureSecurity)
{
      RemotingConfigHandler.DoConfiguration(filename, ensureSecurity);
      RemotingServices.InternalSetRemoteActivationConfigured();
}

跟蹤到DoConfiguration()方法中去,如下:

internal static void DoConfiguration(string filename, bool ensureSecurity)
{
      RemotingConfigHandler.LoadMachineConfigIfNecessary();
      RemotingXmlConfigFileData data1 = RemotingConfigHandler.LoadConfigurationFromXmlFile(filename);
      if (data1 != null)
      {
            RemotingConfigHandler.ConfigureRemoting(data1, ensureSecurity);
      }
}

繼續探查RemotingConfigHandler的ConfigureRemoting

private static void ConfigureRemoting(RemotingXmlConfigFileData configData, bool ensureSecurity)
{
      try
      {
            string text1 = configData.ApplicationName;
            if (text1 != null)
            {
                  RemotingConfigHandler.ApplicationName = text1;
            }
            if (configData.CustomErrors != null)
            {
                  RemotingConfigHandler._errorMode = configData.CustomErrors.Mode;
            }
            RemotingConfigHandler.ConfigureChannels(configData, ensureSecurity);
            if (configData.Lifetime != null)
            {
                  if (configData.Lifetime.IsLeaseTimeSet)
                  {
                        LifetimeServices.LeaseTime = configData.Lifetime.LeaseTime;
                  }
                  if (configData.Lifetime.IsRenewOnCallTimeSet)
                  {
                        LifetimeServices.RenewOnCallTime = configData.Lifetime.RenewOnCallTime;
                  }
                  if (configData.Lifetime.IsSponsorshipTimeoutSet)
                  {
                        LifetimeServices.SponsorshipTimeout = configData.Lifetime.SponsorshipTimeout;
                  }
                  if (configData.Lifetime.IsLeaseManagerPollTimeSet)
                  {
                        LifetimeServices.LeaseManagerPollTime = configData.Lifetime.LeaseManagerPollTime;
                  }
            }
            RemotingConfigHandler._bUrlObjRefMode = configData.UrlObjRefMode;
            RemotingConfigHandler.Info.StoreRemoteAppEntries(configData);
            RemotingConfigHandler.Info.StoreActivatedExports(configData);
            RemotingConfigHandler.Info.StoreInteropEntries(configData);
            RemotingConfigHandler.Info.StoreWellKnownExports(configData);
            if (configData.ServerActivatedEntries.Count > 0)
            {
                  ActivationServices.StartListeningForRemoteRequests();
            }
      }
      catch (Exception exception1)
      {
            throw new RemotingException(string.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_ConfigurationFailure"), new object[] { exception1 }));
      }
}

在此方法中繼續尋找使用那個ensureSecurity參數的地方,顯然裏面是要使用該參數配置通道,再跟進去

private static void ConfigureChannels(RemotingXmlConfigFileData configData, bool ensureSecurity)
{
      RemotingServices.RegisterWellKnownChannels();
      foreach (RemotingXmlConfigFileData.ChannelEntry entry1 in configData.ChannelEntries)
      {
            if (!entry1.DelayLoad)
            {
                  IChannel channel1 = RemotingConfigHandler.CreateChannelFromConfigEntry(entry1);
                  ChannelServices.RegisterChannel(channel1, ensureSecurity);
            }
            else
            {
                  RemotingConfigHandler._delayLoadChannelConfigQueue.Enqueue(new DelayLoadClientChannelEntry(entry1, ensureSecurity));
            }
      }
}

這時我們看到了
ChannelServices.RegisterChannel(channel1, ensureSecurity);
通常我們會用ChannelServices.RegisterChannel(channel1),但此時.NET會提示我們該方法也已過期。原來,
RemotingConfiguration.Configure (String, Boolean)其實就是ChannelServices.RegisterChannel(channel1, ensureSecurity)方法的一個最上層包裝罷了,它要將用戶設置的ensureSecurity參數值一層層的傳遞到ChannelServices.RegisterChannel方法中去。在Msdn中我們可以找到對該方法的第二個參數的說明:
ensureSecurity
true ensures that security is enabled; otherwise false. Setting the value to false will not nullify the security setting done on the TCP or IPC channel. For details, see Remarks.
Remarks
……
If the ensureSecurity parameter is set to true, the remoting system determines whether the channel implements ISecurableChannel, and if so, enables encryption and digital signatures. An exception is thrown if the channel does not implement ISecurableChannel. Note: 
Setting ensureSecurity to true throws a RemotingException for  TcpServerChannel on win98 (Since secure tcp channel is not supported on wi9x)  , and for Http Server Channel on all platforms (Users need to host service in IIS if they want secure http channel).
這下我們因該明白了ensureSecurity參數其實是用來設置註冊通道安全性的。


分別使用HttpChannel和TcpChannel的例子

static void Main(string[] args)
        {
            Console.WriteLine("Host Started.");
            //Channel Registeration
            HttpChannel c = new HttpChannel(3200);
            ChannelServices.RegisterChannel(c,true);
            //Type Registeration-Use server-activated object(SAO)
            //Type is sepecified as (namespace.class)
            Type ServerType = typeof(SimpleServer.MessageManager);
            RemotingConfiguration.RegisterWellKnownServiceType(
                ServerType,//Type of object
                "MyObject",//Arbitrary name
                WellKnownObjectMode.SingleCall);
            Console.Read(); //Keep host running
        }
 
static void Main()
        {
            Console.WriteLine("Host Started.");
            //Channel Registration
            TcpChannel c = new TcpChannel(3200);
            //c.IsSecured = true;
            ChannelServices.RegisterChannel(c, true);
            //Type Registeration
            Type ServerType = typeof(MessageManager);
            RemotingConfiguration.RegisterWellKnownServiceType(
                ServerType,    //Type of object
                "MyObject",    //Arbitrary name
                WellKnownObjectMode.Singleton);
            Console.Read();
           
        }

運行第一個例子,馬上會拋出一個RemotingException: “利用集成 Windows 身份驗證在 IIS 中承載此服務,以保護服務器”,而運行第二個例子,卻不會有任何問題,why?
這是因爲:

下表對兩個主要的傳輸通道接收進行了比較



原來,Remoting沒有自己的安全模型,客戶端(代理)和服務器(遠程對象)之間的身份驗證和授權是通過通道和主機進程執行的。可以組合使用以下的主機和通道:
1、自定義的可執行文件和TCP通道。這種組合不提供任何內置的安全功能。
2、 ASP.NET和HTTP通道。這種組合通過基本的ASP.NET和IIS安全功能提供身份驗證和授權。
在上面的第一個例子中,由於我們並沒有提供相應的身份驗證憑證,所以會拋出那樣的異常,顯然是IIS進行身份驗證時出現錯誤。而在第二個例子中,由於對TCP通道沒有設置安全功能,所以將ensureSecurity設置爲True和False都是一樣的,即都可以正常的工作。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章