2

我已经使用 wsDualHttpBinding 构建了一个简单的 WCF 服务。它在本地运行良好,但是当我在不同的服务器上发布服务并尝试在 WPF 项目中使用该服务时会引发错误。

错误:

System.ServiceModel.SecurityNegotiationException     "The caller was not authenticated by the service."

内部异常:

System.ServiceModel.FaultException        "The caller was not authenticated by the service." 

服务器配置:

<system.serviceModel>
    <services>
      <service name="VetChat.Service.VetChatService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">
        <!-- Service Endpoints -->
        <host>
          <baseAddresses>
            <add baseAddress="http://service.softprodigy.com:8090/VetChatService.svc"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="wsDualHttpBinding" contract="VetChat.Service.IVetChatService">
          <!--
              Upon deployment, the following identity element should be removed or replaced to reflect the
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity
              automatically.
          -->

          <identity>
            <dns value="VPS" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="wsDualHttpBinding.SampleServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="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="true"/>

          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="VetChat.Service.UserNamePassValidator, VetChat.Service" />

            <serviceCertificate findValue="MyName" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName" />

          </serviceCredentials>

        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

客户端配置:

<system.serviceModel>
    <bindings>
      <wsDualHttpBinding>
        <binding name="WSDualHttpBinding_IVetChatService" />
      </wsDualHttpBinding>
    </bindings>

    <client>
      <endpoint address="http://service.softprodigy.com:8090/VetChatService.svc"
        binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IVetChatService"
        contract="ServiceReference1.IVetChatService" name="WSDualHttpBinding_IVetChatService">
        <identity>
          <dns value="VPS" />
        </identity>
      </endpoint>
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CustomBehavior">
          <clientCredentials>

            <clientCertificate findValue="MyName" x509FindType="FindBySubjectName"
          storeLocation="CurrentUser" storeName="TrustedPeople" />
            <serviceCertificate>

              <defaultCertificate findValue="MyName" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName" />


              <authentication certificateValidationMode="PeerTrust" />
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>

    </behaviors>

  </system.serviceModel>

界面:

[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
    public interface IVetChatService
    {
       [OperationContract(IsOneWay = true)]
        void DoWork();
    }

    public interface ICallback
    {
        [OperationContract(IsOneWay = true)]
        void Notify(string value);
    }

接口实现:

public class VetChatService : IVetChatService
    {
        public void DoWork()
        {
            //Thread.Sleep(5000);
            OperationContext.Current.GetCallbackChannel<ICallback>().Notify("Hello");

        }
    }

验证用户名密码服务类:

namespace VetChat.Service
{
    class UserNamePassValidator :
          System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == null || password == null)
            {
                throw new ArgumentNullException();
            }

            if (!(userName == UserName && password == Password))
            {
                //throw new FaultException("Incorrect Username or Password");
            }
        }
    }
    public class Service
    {
    }
}

调用方式:

    InstanceContext instanceContext = new InstanceContext(new SampleServiceCallback());

    ServiceReference1.VetChatServiceClient sampleServiceClient = new ServiceReference1.VetChatServiceClient(instanceContext);


    sampleServiceClient.ClientCredentials.ClientCertificate.SetCertificate(
           StoreLocation.CurrentUser,
           StoreName.TrustedPeople,
           X509FindType.FindBySubjectName,
           "MyName");
    sampleServiceClient.ClientCredentials.UserName.UserName = UserName;
    sampleServiceClient.ClientCredentials.UserName.Password = Password;
    //sampleServiceClient.Open();
    sampleServiceClient.DoWork();

响应回调:

public class SampleServiceCallback : ServiceReference1.IVetChatServiceCallback
    {

        #region ISampleServiceCallback Members

        public void Notify(string value)
        {
            MessageBox.Show(value);
        }

        #endregion
    }

谢谢

4

0 回答 0