我有一个启用了wsHttpBindings和SSL的WCF服务,但是我想启用WCF会话。
将SessionMode更改为必需
SessionMode:=SessionMode.Required
我收到的错误如下所述。
合同需要Session,但Binding'WSHttpBinding'不支持 它或没有正确配置以支持它。
这是我的示例应用程序。
的App.config
<?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
TestService.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 ,但我想使用我当前的配置启用会话,如果可能的话。
有没有办法实现这个目标?
非常感谢任何形式的帮助。
答案 0 :(得分:19)
如果您想要与wsHttpBinding“会话”,则必须使用可靠的消息传递或安全会话。 (来源:how to enable WCF Session with wsHttpBidning with Transport only Security)。
WSHttpBinding支持会话,但仅在启用安全性(SecureConversation)或可靠消息传递时才支持。 如果您正在使用传输安全性,则它不使用WS-SecureConversation,并且默认情况下WS-ReliableMessaging处于关闭状态。因此,WSHttpBinding用于会话的两个协议不可用。您需要使用邮件安全性或打开可靠的会话。 (来源:http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/57b3453e-e7e8-4875-ba23-3be4fff080ea/)。
我们在标准绑定中禁止使用RM而不是Https,因为保护RM会话的方法是使用安全会话而Https不提供会话。
我在这里发现了msdn blurb:http://msdn2.microsoft.com/en-us/library/ms733136.aspx 模糊是“唯一的例外是使用HTTPS时。 SSL会话未绑定到可靠会话。这会产生威胁,因为共享安全上下文(SSL会话)的会话不会相互保护;这可能是也可能不是真正的威胁,具体取决于应用程序。“
但是,如果您确定没有威胁,则可以执行此操作。通过自定义绑定http://msdn2.microsoft.com/en-us/library/ms735116.aspx有一个RM over HTTPS示例(来源: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配置,我只测试了服务激活,而不是调用。
编辑:根据用户请求,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
答案 1 :(得分:1)
默认情况下,WSHttpBinding仅允许安全会话。它是WCF的概念,与Transport无关。安全会话不是通过https的会话,而是具有相互身份验证的会话。这是通过添加消息安全性来实现的。
根据您的服务,您应该应用此配置
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingConfig">
<security mode="TransportWithMessageCredential">
<!-- configure transport & message security here if needed-->
</security>
</binding>
</wsHttpBinding>
</bindings>
在客户端,这是一个简单的单元测试
[TestMethod]
public void TestSecuritySession()
{
//remove this is certificate is valid
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) => { return true; });
var binding = new WSHttpBinding();
binding.Security = new WSHttpSecurity() { Mode = SecurityMode.TransportWithMessageCredential};
ChannelFactory<ITestService> Factory = new ChannelFactory<ITestService>(binding, new EndpointAddress("https://localhost/TestService.svc"));
Factory.Open();
var channel = Factory.CreateChannel();
//call service here
(channel as IClientChannel).Close();
Factory.Close();
}
答案 2 :(得分:1)
wsHttpBinding需要reliableSession来支持WCF会话,可靠的会话需要自定义绑定来支持ssl。因此,就我所知,在ssl和wsHttpBinding上请求WCF会话似乎是不可能的。