新项目中使用了WCF 实现客户端与服务器的通讯。c/s架构,客户端采用winfrom实现。项目试运行期间,很多用户都抱怨系统总是无法正常登录。
查看日志发现如下异常信息:
System.ServiceModel.Security.MessageSecurityException: 从另一方收到未进行安全处理或安全处理不正确的错误。有关错误代码和详细信息,请
参阅内部 FaultException。 ---> System.ServiceModel.FaultException: 消息中至少有一个安全令牌无法验证。
WCF通讯采用了UserName安全认证方式,用Google大神搜索一番,上述异常多是因为客户端与服务器端时间不同步所引起的,WCF所提供的几种Binding客户端和服务端所允许的时间差可以是5分钟.
原因找到了,下面就是如何解决了,网上大多数方法是使用 命令:net time \\IP地址或服务器名 /set /yes 去同步客户端的时间,这种方式我直接给Pass掉了,原因如下:
通过跟用户的交流发现很多用户是故意将时间提前或推后十几分钟的,原因很多就不详细列具了。
继续找其它解决方案,在国外一个论坛上发现可以使用customBinding 修改允许的最大时间偏差。let's try it!
修改前的配置文件(删减了一些配置节)如下:
<system.serviceModel>
<client/>
<services>
<service name="userService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding_user"
contract="Iuser"/>
</service>
<bindings>
<wsHttpBinding>
<binding name="Binding_user">
<security mode="Message">
<transport/>
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
将wsHttpBinding替换为customBinding后配置文件如下:
<system.serviceModel>
<client/>
<services>
<service name="userService">
<endpoint address="" binding="customBinding" bindingConfiguration="MyCustomBinding"
contract="Iuser"/>
</service>
</services>
<bindings>
<customBinding>
<binding name="MyCustomBinding">
<transactionFlow />
<security authenticationMode="UserNameForSslNegotiated">
<secureConversationBootstrap>
<localClientSettings maxClockSkew="00:59:00" />
<localServiceSettings maxClockSkew="00:59:00" />
</secureConversationBootstrap>
<localClientSettings maxClockSkew="00:59:00" />
<localServiceSettings maxClockSkew="00:59:00" />
</security>
<textMessageEncoding>
<readerQuotas maxStringContentLength="500000"/>
</textMessageEncoding>
<httpTransport maxReceivedMessageSize="10485760" maxBufferPoolSize="524288" />
</binding>
</customBinding>
</bindings>
</system.serviceModel>
这里将充许的最大时间偏差改为59分钟。
到这里还不算完,以上只是修改的服务端配置文件,在客户端的app.config文件中同样要修改,客户端配置修改后如下:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="MyCustomBinding" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
>
<transactionFlow />
<security authenticationMode="UserNameForSslNegotiated">
<secureConversationBootstrap>
<localClientSettings maxClockSkew="00:59:00" />
<localServiceSettings maxClockSkew="00:59:00" />
</secureConversationBootstrap>
<localClientSettings maxClockSkew="00:59:00" />
<localServiceSettings maxClockSkew="00:59:00" />
</security>
<textMessageEncoding>
<readerQuotas maxStringContentLength="500000"/>
</textMessageEncoding>
<httpTransport maxReceivedMessageSize="10485760" maxBufferPoolSize="524288" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://********/user.svc" binding="customBinding"
bindingConfiguration="MyCustomBinding" contract="Iuser"
name="CustomBinding_Iuser" />
</client>
</system.serviceModel>
OK,完工,初次写博,尽请拍砖。
有关CustomBinding的详细使用请参见Msdn-<customBinding>