首页 > 解决方案 > WCF x509 证书消息身份验证在 VS 2019 中内置时有效,但在自托管时失败

问题描述

我创建了一个 WCF 服务和一个简单的表单应用程序来访问它。到目前为止,在添加证书之前,一切正常,我能够成功地从服务中获得回报。

在尝试了证书之后,我已经能够更新客户端和服务中的配置,因此当从 Visual Studio 构建时,应用程序可以使用证书完美运行。

我的问题是当使用自托管控制台应用程序在 Visual Studio 之外托管服务时,我收到“无法打开安全通道,因为与端点的安全协商失败。这可能是由于 EndpointAddress 中缺少或错误指定 EndpointIdentity用于创建频道。” 错误。

只是想知道是否有人可以在我的配置中看到任何可能导致此问题的明显错误?就像我说的,它在 Visual Studio 挂载服务时工作,但是自托管中的某些东西会导致错误。

仅供参考:客户端跟踪只是说我上面说的错误。服务器跟踪甚至不显示。WCFTestClient 还表示正在托管该服务。

干杯!

客户:

<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
                 switchValue="Information, ActivityTracing"
                 propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData="c:\Client.svclog"  />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <system.serviceModel>
      <behaviors>
        <endpointBehaviors>
          <behavior name="endpointCredentialsBehavior">
            <clientCredentials>
              <clientCertificate findValue="TraceCert"
                                 storeLocation="LocalMachine"
                                 x509FindType="FindBySubjectName"/>
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>
        <bindings>
            <wsHttpBinding>
                <binding name="clientBinding">
                    <security>
                        <message clientCredentialType="Certificate" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8000/ContactTraceWCF" binding="wsHttpBinding"
                bindingConfiguration="clientBinding" contract="ContactTraceServer.IContactTraceServer"
                name="WSHttpBinding_IContactTraceWCF" behaviorConfiguration="endpointCredentialsBehavior">
                <identity>
                    <dns value="TraceRootCA" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

服务器:

<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
                 switchValue="Information, ActivityTracing"
                 propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "c:\Server.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
  <system.serviceModel>
    <services>
      <service name="ContactTraceWCF.ContactTraceServer">
        <endpoint address="" 
                  binding="wsHttpBinding" 
                  bindingConfiguration="WSHttpBinding_IContactTraceWCF"
                  contract="ContactTraceWCF.IContactTraceServer"
                  name="WSHttpBinding_IContactTraceWCF">
          <identity>
            <dns value="TraceRootCA" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/ContactTraceWCF" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="True" />
          <serviceCredentials>
            <serviceCertificate findValue="TraceRootCA"
                                storeLocation="CurrentUser"
                                x509FindType="FindBySubjectName"/>
            <clientCertificate>
              <authentication certificateValidationMode="None"/>
            </clientCertificate>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IContactTraceWCF">
          <security mode="Message">
            <message clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

主机控制台应用程序:

    using (ServiceHost serviceHost = new ServiceHost(typeof(ContactTraceServer), new Uri("http://localhost:8000/ContactTraceWCF")))
    {
        try
        {
            serviceHost.AddServiceEndpoint(typeof(IContactTraceServer), new WSHttpBinding(), "");

            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            serviceHost.Description.Behaviors.Add(smb);
            serviceHost.Open();

            Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.ReadLine();
            serviceHost.Close();
        }
        catch (TimeoutException timeProblem)
        {
            Console.WriteLine(timeProblem.Message);
            Console.ReadLine();
        }
        catch (CommunicationException commProblem)
        {
            Console.WriteLine(commProblem.Message);
            Console.ReadLine();
        }
    }

标签: c#wcfx509certificateself-hosting

解决方案


所以经过一番测试,我发现在创建self host的时候,并没有从WCF服务的app.config中拉取,所以在构建servicehost的时候基本都要重写。

我提供了下面对我有用的代码。

    using (ServiceHost serviceHost = new ServiceHost(typeof(ContactTraceServer), new Uri("http://localhost:8000/")))
    {
        try
        {
            var binding = new WSHttpBinding();
            binding.Security.Mode = SecurityMode.Message;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
            serviceHost.AddServiceEndpoint(typeof(IContactTraceServer), binding, "ContactTraceWCF");
            serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "TraceRootCA");
            serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            serviceHost.Description.Behaviors.Add(smb);
            serviceHost.Open();


            Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.ReadLine();
            serviceHost.Close();
        }
        catch (TimeoutException timeProblem)
        {
            Console.WriteLine(timeProblem.Message);
            Console.ReadLine();
        }
        catch (CommunicationException commProblem)
        {
            Console.WriteLine(commProblem.Message);
            Console.ReadLine();
        } catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.ReadLine();
        }
    }

推荐阅读