使用 net.tcp 绑定在 wcf 中设置最大时间偏差

Set max time skew in wcf with net.tcp binding

我有一个带有 net.tcp 端点的 WCF 服务,使用自定义用户名密码验证器、自定义授权和 TransportWithMessageCredential 凭证类型 "Username"(见下文)。 服务器和客户端工作正常 - 除非服务器和客户端计算机之间的时间偏差超过 5 分钟。

现在我尝试在代码中设置最大偏移时间。我尝试从 MSDN 改编用于 WSHttpBindings 的代码片段,并在服务器和客户端上使用自定义绑定:

binding = GetSecuredBindingFromServerOrClient(); 
CustomBinding myCustomBinding = new CustomBinding(binding);
var security = myCustomBinding.Elements.Find<TransportSecurityBindingElement>(); // TransportSecurityBindingElement or SecurityBindingElement
security.LocalClientSettings.MaxClockSkew = timeSkew;
security.LocalServiceSettings.MaxClockSkew = timeSkew;
security.LocalServiceSettings.DetectReplays = false;
security.IncludeTimestamp = false;
// on client: use this custom binding in channel factory
var channelFactory = new ChannelFactory<ICheckerService>(customBinding, someAddress);
// on server: Update binding with customBinding
endpoint.Binding = myCustomBinding;

当时间偏差超过 5 分钟(默认值)时,连接仍然失败并显示 MessageSecurityException。我也将 IncludeTimestamp 设置为 false 或 true,但它们都没有改善这种情况。

服务器行为是:

<behavior name="customUserNamePasswordSecurityBehavior">
 <serviceCredentials>
   <userNameAuthentication userNamePasswordValidationMode="Custom"  customUserNamePasswordValidatorType="MySecurity.BasicAuthenticationValidator, MySecurity.Services"/>
 </serviceCredentials>
 <serviceAuthorization principalPermissionMode="Custom">
   <authorizationPolicies>
     <add policyType="Security.CustomAuthorizationPolicy, MySecurity.Services"/>
   </authorizationPolicies>
 </serviceAuthorization>
</behavior>

那么端点绑定是:

<binding name="tcpUserNameAuthentication">
   <reliableSession enabled="true"/>
   <security mode="TransportWithMessageCredential">
      <message clientCredentialType="UserName"/>
   </security>
</binding>

是否有人根据上述配置使用 TransportWithMessageCredential 和 net.tcp 解决时间偏差问题?还是存在基本的误解?

在我这边,如果我使用NetTcp协议,MaxClockSkew效果很好,它需要服务器端的证书(需要将私钥的管理权限添加到帐户运行服务)和username/password 在客户端。
首先,我将 Nettcpbinding 转换为 Custombinding。

<customBinding>
        <binding name="mybinding">
          <security authenticationMode="SecureConversation">
            <localClientSettings maxClockSkew="00:07:00" />
            <localServiceSettings maxClockSkew="00:07:00" />
            <secureConversationBootstrap authenticationMode="UserNameForCertificate">
              <localClientSettings maxClockSkew="00:30:00" />
              <localServiceSettings maxClockSkew="00:30:00" />
            </secureConversationBootstrap>
          </security>
          <binaryMessageEncoding></binaryMessageEncoding>
          <tcpTransport />
        </binding>
      </customBinding>

然后我用客户端代理调用服务 class 当我在客户端更改时间时,当客户端时间在服务器端变化在 7 分钟以内时它工作正常。如果我没有在服务器端设置 MaxClockSkew。它只能在服务器端时间的 5 分钟内工作。
请参考下面的例子,希望对你有用。
服务器端(控制台应用程序)

class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost sh=new ServiceHost(typeof(MyService)))
            {
                sh.Open();
                Console.WriteLine("Service is ready....");

                Console.ReadLine();
                sh.Close();
            }
        }
    }

    [ServiceContract]
    interface IService
    {
        [OperationContract]
        string GetData();
    }
    public class MyService : IService
    {
        public string GetData()
        {
            return DateTime.Now.ToString();
        }
    }
    public class MyValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName != "jack" || password != "123456")
            {
                throw new Exception("My Error");
            }

        }
    }

App.config

<system.serviceModel>
    <services>
      <service name="Server1.MyService" behaviorConfiguration="mybehavior">
        <endpoint address="" binding="customBinding" contract="Server1.IService" bindingConfiguration="mybinding"></endpoint>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"></endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:800"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <bindings>
      <customBinding>
        <binding name="mybinding">
          <security authenticationMode="SecureConversation">
            <localClientSettings maxClockSkew="00:07:00" />
            <localServiceSettings maxClockSkew="00:07:00" />
            <secureConversationBootstrap authenticationMode="UserNameForCertificate">
              <localClientSettings maxClockSkew="00:30:00" />
              <localServiceSettings maxClockSkew="00:30:00" />
            </secureConversationBootstrap>
          </security>
          <binaryMessageEncoding></binaryMessageEncoding>
          <tcpTransport />
        </binding>
      </customBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="mybehavior">
          <serviceMetadata />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <serviceCertificate findValue="5ba5022f527e32ac02548fc5afc558de1d314cb6" x509FindType="FindByThumbprint" storeLocation="LocalMachine" storeName="My"/>
            <userNameAuthentication customUserNamePasswordValidatorType="Server1.MyValidator,Server1" userNamePasswordValidationMode="Custom"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

客户端。

ServiceReference1.ServiceClient client = new ServiceClient();
            client.ClientCredentials.UserName.UserName = "jack";
            client.ClientCredentials.UserName.Password = "123456";
            try
            {
                var result = client.GetData();
                Console.WriteLine(result);
            }
            catch (Exception)
            {
                throw;
            }

App.config(自动生成)

<system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="CustomBinding_IService">
                    <security defaultAlgorithmSuite="Default" authenticationMode="SecureConversation"
                        requireDerivedKeys="true" includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                        requireSignatureConfirmation="false" canRenewSecurityContextToken="true">
                        <secureConversationBootstrap defaultAlgorithmSuite="Default"
                            authenticationMode="UserNameForCertificate" requireDerivedKeys="true"
                            includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                            requireSignatureConfirmation="false">
                            <localClientSettings detectReplays="true" />
                            <localServiceSettings detectReplays="true" />
                        </secureConversationBootstrap>
                        <localClientSettings detectReplays="true" />
                        <localServiceSettings detectReplays="true" />
                    </security>
                    <binaryMessageEncoding />
                    <tcpTransport />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://10.157.13.69:800/" binding="customBinding"
                bindingConfiguration="CustomBinding_IService" contract="ServiceReference1.IService"
                name="CustomBinding_IService">
                <identity>
                    <certificate encodedValue="blablabla" />
                </identity>
            </endpoint>
        </client>
</system.serviceModel>

如果有什么我可以帮忙的,请随时告诉我。