Dot-Net

如何在 WCF 中啟用帶有 SSL wsHttpBinding 的會話

  • October 4, 2012

我有一個啟用了 wsHttpBindings 和 SSL 的 WCF 服務,但我想啟用 WCF 會話。

將 SessionMode 更改為 required 後

SessionMode:=SessionMode.Required

 我收到下面描述的錯誤。 

契約需要 Session,但 Binding ‘WSHttpBinding’ 不支持它或未正確配置以支持它。

這是我的範例應用程序。

應用程序配置

 <?xml version="1.0" encoding="utf-8" ?>
   <configuration>

     <system.web>
       <compilation debug="true" />
     </system.web>
     <!-- When deploying the service library project, the content of the config file must be added to the host's 
     app.config file. System.Configuration does not support config files for libraries. -->
     <system.serviceModel>

       <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
       <client />
       <bindings>
         <wsHttpBinding>
           <binding name="NewBinding0" useDefaultWebProxy="false" allowCookies="true">
             <readerQuotas maxStringContentLength="10240" />
             <!--reliableSession enabled="true" /-->
             <security mode="Transport">
               <transport clientCredentialType="None" proxyCredentialType="None" >
                 <extendedProtectionPolicy policyEnforcement="Never" />
               </transport >
             </security>
           </binding>
         </wsHttpBinding>
       </bindings>
       <services>
         <service name="WcfServiceLib.TestService">
           <endpoint address="" binding="wsHttpBinding" bindingConfiguration="NewBinding0"
             contract="WcfServiceLib.ITestService">
             <identity>
               <servicePrincipalName value="Local Network" />
             </identity>
           </endpoint>
           <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
           <host>
             <baseAddresses>
               <add baseAddress="https://test/TestService.svc" />
             </baseAddresses>
           </host>
         </service>
       </services>

       <behaviors>
         <serviceBehaviors>
           <behavior>
             <!-- To avoid disclosing metadata information, 
             set the value below to false and remove the metadata endpoint above before deployment -->
             <serviceMetadata httpsGetEnabled="True"/>
             <!-- To receive exception details in faults for debugging purposes, 
             set the value below to true.  Set to false before deployment 
             to avoid disclosing exception information -->
             <serviceDebug includeExceptionDetailInFaults="False" />
           </behavior>
         </serviceBehaviors>
       </behaviors>
     </system.serviceModel>

   </configuration>

ITestService.vb

 <ServiceContract(SessionMode:=SessionMode.Required)>
   Public Interface ITestService

       <OperationContract(IsInitiating:=True, IsTerminating:=False)> _
       Function GetData(ByVal value As Integer) As String

   End Interface

測試服務.vb

   <ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession, _ 
   ReleaseServiceInstanceOnTransactionComplete:=False, _ 
   ConcurrencyMode:=ConcurrencyMode.Single)>
       Public Class TestService
           Implements ITestService

           Private _user As User

           <OperationBehavior(TransactionScopeRequired:=True)>
           Public Function GetData(ByVal value As Integer) As String _
Implements ITestService.GetData

               If _user Is Nothing Then

                   _user = New User()
                   _user.userName = "User_" & value
                   _user.userPassword = "Pass_" & value

                   Return String.Format("You've entered: {0} , Username = {1} , Password = {2} ", _
                                        value, _user.userName, _user.userPassword)
               Else
                   Return String.Format("Username = {1} , Password = {2} ", _
                                   _user.userName, _user.userPassword)
               End If

           End Function

       End Class

我嘗試了所有可能的解決方案,我可以找到,但沒有任何幫助。

一些啟用可靠會話的建議,但它不適用於ssl(如果只有您有自定義綁定),其他建議使用http而不是https,但如果可能的話,我想使用我目前的配置啟用 Sessions .

有什麼方法可以實現這一目標嗎?

非常感謝任何形式的幫助。

如果您想使用 wsHttpBinding 進行“會話”,則必須使用可靠消息傳遞或安全會話。(來源:如何使用 wsHttpBidning 和 Transport only Security 啟用 WCF 會話)。

WSHttpBinding 支持會話,但前提是啟用了安全性 (SecureConversation) 或可靠消息傳遞。如果您使用傳輸安全性,那麼它不使用 WS-SecureConversation 並且預設情況下 WS-ReliableMessaging 處於關閉狀態。因此 WSHttpBinding 用於會話的兩種協議不可用。您要麼需要使用消息安全性,要麼需要打開可靠會話。(來源:http ://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/ )。

我們在標準綁定中不允許 RM over Https,因為保護 RM 會話的方法是使用安全會話,而 Https 不提供會話。

我在這裡找到了關於它的 msdn 簡介:http: //msdn2.microsoft.com/en-us/library/ms733136.aspx 簡介是“唯一的例外是使用 HTTPS 時。SSL 會話未綁定到可靠會話。這造成了威脅,因為共享安全上下文(SSL 會話)的會話彼此之間沒有受到保護;這可能是也可能不是真正的威脅,具體取決於應用程序。”

但是,如果您確定沒有威脅,您可以這樣做。通過自定義綁定有一個 RM over HTTPS 範例http://msdn2.microsoft.com/en-us/library/ms735116.aspx(來源:http ://social.msdn.microsoft.com/forums/en-US/ wcf/thread/fb4e5e31-e9b0-4c24-856d-1c464bd0039c/)。

總結您的可能性,您可以:

1 - 保留 wsHttpBinding,刪除傳輸安全性並啟用可靠消息傳遞

 <wsHttpBinding>
   <binding name="bindingConfig">
     <reliableSession enabled="true" />
     <security mode="None"/>
   </binding>
 </wsHttpBinding>

但是你失去了 SSL 層,然後是你的安全性的一部分。

2 - 保留 wsHttpBinding,保持傳輸安全並添加消息認證

 <wsHttpBinding>
   <binding name="bindingConfig">
     <security mode="TransportWithMessageCredential">
       <message clientCredentialType="UserName"/>
     </security>
   </binding>
 </wsHttpBinding>

您可以保留 SSL 安全層,但您的客戶端必須提供憑據(任何形式),即使您不在服務端驗證它們,仍然必須提供假的,因為 WCF 將拒絕任何未指定憑據的消息.

3 - 使用具有可靠消息傳遞和 HTTPS 傳輸的自定義綁定

 <customBinding>
   <binding name="bindingConfig">
     <reliableSession/>
     <httpsTransport/>
   &lt;/binding&gt;
 &lt;/customBinding&gt;

除了 MSDN 中解釋的威脅外,我看不出有任何不利之處,這取決於您的應用程序。

4 - 使用其他會話提供程序如果您的應用程序在 IIS 中熱,您可以設置

&lt;serviceHostingEnvironment aspNetCompatibilityEnabled="true"/&gt;

並取決於

HttpContext.Current.Session

為你的州。

或實施您自己的 cookie。

PS:請注意,對於所有這些 WCF 配置,我只測試了服務啟動,而不是呼叫。

編輯:根據使用者請求,wsHttpBinding使用TransportWithMessageCredential安全模式實現會話(我對 VB.NET 不太熟悉,所以請原諒我的語法):

服務程式碼片段:

&lt;ServiceContract(SessionMode:=SessionMode.Required)&gt;
Public Interface IService1

   &lt;OperationContract()&gt; _
   Sub SetSessionValue(ByVal value As Integer)

   &lt;OperationContract()&gt; _
   Function GetSessionValue() As Nullable(Of Integer)

End Interface

&lt;ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession, 
   ConcurrencyMode:=ConcurrencyMode.Single)&gt;
Public Class Service1
   Implements IService1

   Private _sessionValue As Nullable(Of Integer)

   Public Sub SetSessionValue(ByVal value As Integer) Implements IService1.SetSessionValue
       _sessionValue = value
   End Sub

   Public Function GetSessionValue() As Nullable(Of Integer) Implements IService1.GetSessionValue
       Return _sessionValue
   End Function
End Class

Public Class MyUserNamePasswordValidator
   Inherits System.IdentityModel.Selectors.UserNamePasswordValidator

   Public Overrides Sub Validate(userName As String, password As String)
       ' Credential validation logic
       Return ' Accept anything
   End Sub

End Class

服務配置片段:

&lt;system.serviceModel&gt;
 &lt;services&gt;
   &lt;service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior"&gt;
     &lt;endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1" bindingConfiguration="bindingConf"/&gt;
     &lt;endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/&gt;
   &lt;/service&gt;
 &lt;/services&gt;
 &lt;bindings&gt;
   &lt;wsHttpBinding&gt;
     &lt;binding name="bindingConf"&gt;
       &lt;security mode="TransportWithMessageCredential"&gt;
         &lt;message clientCredentialType="UserName"/&gt;
       &lt;/security&gt;
     &lt;/binding&gt;
   &lt;/wsHttpBinding&gt;
 &lt;/bindings&gt;
 &lt;behaviors&gt;
   &lt;serviceBehaviors&gt;
     &lt;behavior name="WcfService1.Service1Behavior"&gt;
       &lt;serviceMetadata httpsGetEnabled="true"/&gt;
       &lt;serviceDebug includeExceptionDetailInFaults="false"/&gt;
       &lt;serviceCredentials&gt;
         &lt;userNameAuthentication 
           userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType="WcfService1.MyUserNamePasswordValidator, WcfService1"/&gt;
       &lt;/serviceCredentials&gt;
     &lt;/behavior&gt;
   &lt;/serviceBehaviors&gt;
 &lt;/behaviors&gt;
&lt;/system.serviceModel&gt;

客戶端測試程式碼片段:

Imports System.Threading.Tasks

Module Module1

   Sub Main()
       Parallel.For(0, 10, Sub(i) Test(i))
       Console.ReadLine()
   End Sub

   Sub Test(ByVal i As Integer)
       Dim client As ServiceReference1.Service1Client
       client = New ServiceReference1.Service1Client()
       client.ClientCredentials.UserName.UserName = "login"
       client.ClientCredentials.UserName.Password = "password"
       Console.WriteLine("Session N° {0} : Value set to {0}", i)
       client.SetSessionValue(i)
       Dim response As Nullable(Of Integer)
       response = client.GetSessionValue()
       Console.WriteLine("Session N° {0} : Value returned : {0}", response)
       client.Close()
   End Sub

End Module

引用自:https://stackoverflow.com/questions/12578409