Ответ 1
Если вы хотите "сеансы" с wsHttpBinding, вам нужно использовать либо надежный обмен сообщениями, либо сеансы безопасности. (источник: как включить сеанс WCF с помощью wsHttpBidning с защитой только для транспорта).
WSHttpBinding поддерживает сеанс, но только если включена защита (SecureConversation) или надежная передача сообщений. Если вы используете транспортную безопасность, то он не использует WS-SecureConversation и WS-ReliableMessaging отключен по умолчанию. Поэтому два протокола, которые WSHttpBinding использует для сеанса, недоступны. Вам нужно либо использовать безопасность сообщений, либо включить надежный сеанс. (источник: http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/).
Weve запретил RM над Https в стандартных привязках, потому что способ защитить сеанс RM - использовать сеанс безопасности, а Https не предоставляет сеанс.
Я нашел здесь сообщение msdn: http://msdn2.microsoft.com/en-us/library/ms733136.aspx Разметка "Единственное исключение - это использование HTTPS. Сессия SSL не связана с надежным сеансом, что накладывает угрозу, поскольку сеансы, совместно использующие контекст безопасности (сеанс SSL), не защищены друг от друга, это может или не может быть реальной угрозой в зависимости от приложения".
Однако вы можете сделать это, если вы определите отсутствие угрозы. Существует образец RM по 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/>
</binding>
</customBinding>
Я не вижу недостатка в этом, кроме угрозы, описанной в MSDN, и это зависит от вашего приложения.
4 - Использовать других поставщиков сеансов Если ваше приложение запущено в IIS, вы можете установить
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
и зависит от
HttpContext.Current.Session
для вашего состояния.
Или внедрить свои собственные файлы cookie.
PS: Обратите внимание, что для всех этих конфигураций WCF я тестировал только активацию службы, а не звонки.
EDIT: по запросу пользователя wsHttpBinding
с TransportWithMessageCredential
режимами безопасности, реализующими сеансы (я не слишком хорошо знаком с VB.NET, поэтому прошу простить мой синтаксис):
Фрагмент кода службы:
<ServiceContract(SessionMode:=SessionMode.Required)>
Public Interface IService1
<OperationContract()> _
Sub SetSessionValue(ByVal value As Integer)
<OperationContract()> _
Function GetSessionValue() As Nullable(Of Integer)
End Interface
<ServiceBehavior(InstanceContextMode:=InstanceContextMode.PerSession,
ConcurrencyMode:=ConcurrencyMode.Single)>
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
сервис-фрагмент конфигурации:
<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">
<endpoint address="" binding="wsHttpBinding" contract="WcfService1.IService1" bindingConfiguration="bindingConf"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="bindingConf">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WcfService1.MyUserNamePasswordValidator, WcfService1"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
фрагмент кода тестового кода клиента:
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