配置 WCF 客户端绑定以在 dotnet core 2.2 中使用 X509 证书

Configuring WCF client binding to use X509 certificate in dotnet core 2.2

我正在尝试将旧的 WCF 客户端转换为 dotnet 核心。我成功地从 wsdl 生成了我的代理,并一直在尝试配置它们,以便我可以成功调用端点。根据一些谷歌搜索,似乎在 dotnet 核心下我需要从代码配置我的 WCF 客户端。

这是旧应用程序 web.config 中的 WCF 配置部分:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <behaviors>
    <endpointBehaviors>
      <behavior name="clientEndpointCredential">
        <clientCredentials>
          <clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName" findValue="CERTNAME" />
        </clientCredentials>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <basicHttpBinding>
      <binding name="OUR_Customer_OUTBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
        <readerQuotas maxDepth="32" maxStringContentLength="5242880" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
        <security mode="Transport">
          <transport clientCredentialType="Certificate" proxyCredentialType="None" realm="" />
        </security>
      </binding>
    </basicHttpBinding>
  </bindings>
  <client>
    <endpoint address="https://the-full-url" behaviorConfiguration="clientEndpointCredential" binding="basicHttpBinding" bindingConfiguration="OUR_Customer_OUTBinding" contract="CustomerInterface.OUR_Customer_OUT" name="HTTPS_Port" />
  </client>
  <diagnostics>
    <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false" maxMessagesToLog="3000" />
  </diagnostics>
</system.serviceModel>

这是我在 dotnet 核心中配置它的方法:

private OUR_Customer_OUTClient GetCustomerClient()
{
    TimeSpan Minutes(int minutes) => new TimeSpan(0, minutes, 0);

    var binding = new BasicHttpBinding();
    binding.Name = "OUR_Customer_OUTBinding";
    binding.AllowCookies = false;
    binding.SendTimeout = Minutes(1);
    binding.ReceiveTimeout = Minutes(10);
    binding.OpenTimeout = Minutes(1);
    binding.CloseTimeout = Minutes(1);
    binding.MaxBufferPoolSize = 2147483647;
    binding.MaxReceivedMessageSize = 2147483647;
    binding.TextEncoding = Encoding.UTF8;
    binding.TransferMode = TransferMode.Buffered;
    binding.BypassProxyOnLocal = false;
    binding.UseDefaultWebProxy = true;
    binding.Security.Mode = BasicHttpSecurityMode.Transport;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
    binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;

    var endpointAddress = new EndpointAddress("https://the-full-url");

    var client = new OUR_Customer_OUTClient(binding, endpointAddress);
    client.ClientCredentials.ClientCertificate.SetCertificate(
        StoreLocation.LocalMachine,
        StoreName.My,
        X509FindType.FindBySubjectName,
        "CERTNAME");
    return client;
}

这是我用来调用端点的代码(dotnet 核心代理尚不支持同步调用):

SearchResponse searchResponse = Task.Run(() => GetCustomerClient().SearchAsync(message)).Result;

但是,我收到以下错误:

HTTP 请求未经客户端身份验证方案 'Anonymous' 授权。从服务器收到的身份验证 header 是 'Basic realm="XISOAPApps"'

任何人都可以看到我的方法有什么问题或建议我可以用来调试它的方法吗?我是一个 WCF 新手,此时我已经抓狂了。

您的代码片段看起来不错。我们可能还有一件事要做。当服务器用证书对客户端进行认证时,我们就应该建立彼此之间的信任关系,请参考下面link.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
此外,我们应该提供一个标识标志来标识服务器,如下所示。

<client>
    <endpoint address="http://vabqia593vm:4434/Service1.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1" name="WSHttpBinding_IService1" behaviorConfiguration="mybeh">
        <identity>
            <dns value="vabqia130vm"/>
        </identity>
    </endpoint>
</client>

我们可以通过 Micorosoft WCF Web 服务引用提供程序生成客户端代理 class。(添加连接的服务)。 如果有什么我可以帮忙的,请随时告诉我。
亚伯拉罕

为了其他不幸遇到同样问题的人的利益,中心问题原来是 X509 证书没有被发送。 (我们命中的端点接受了证书或基本身份验证,因此是 401。)

未发送证书的原因是 dotnet 核心网络堆栈比 .NET 堆栈更严格,并且要求证书具有其 增强型密钥用法设置为 ClientAuthentication (1.3.6.1.5.5.7.3.2) 或根本没有 EKU(参见 source code here)。我们的不是 - 它被设置为服务器身份验证。所以证书被悄悄丢弃了,尽管已经加载成功。

This github issue 提供了更多详细信息。