如何在WebClient (C#)中添加证书?

79

我知道使用HttpWebRequest添加证书很简单。但是,我还没有找到一种使用WebClient实现相同功能的方法。基本上,我想使用WebClient发送具有特定证书的POST请求。

您将如何使用WebClient完成此代码:

var request = (HttpWebRequest) WebRequest.Create("my-url");
request.Method = "POST";
request.ClientCertificates.Add(new X509Certificate()); //add cert

1
对于未来的问题寻求者,请注意,微软建议使用较新的HttpClient而不是WebClient:我们不建议您在新开发中使用WebClient类。相反,请使用System.Net.Http.HttpClient类。 - Alex
4个回答

103

你必须继承并覆盖一个或多个函数。

class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
        request.ClientCertificates.Add(new X509Certificate());
        return request;
    }
}

太棒了!我已经试图弄清楚如何做这件事太久太久了。 - RandomInsano

12
public class CertificateWebClient : WebClient
{
    private readonly X509Certificate2 certificate;

    public CertificateWebClient(X509Certificate2 cert)
    {
        certificate = cert;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);

        System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate X509certificate, X509Chain chain, System.Net.Security.SslPolicyErrors errors)
        {
            return true;
        };

        request.ClientCertificates.Add(certificate);
        return request;
    }
}

现在您可以使用自签名证书!(“基础连接已关闭:无法建立 SSL/TLS 安全通道的信任关系;基础连接已关闭:无法建立 SSL/TLS 安全通道的信任关系;”)

        X509Certificate2 Cert = new X509Certificate2("client.p12", "1234", X509KeyStorageFlags.MachineKeySet);

        // Create a new WebClient instance.
        CertificateWebClient myWebClient = new CertificateWebClient(Cert);

        string fileName = Installation.destXML;
        string uriString = "https://xxxxxxx.xx:918";
        // Upload the file to the URI.
        // The 'UploadFile(uriString,fileName)' method implicitly uses HTTP POST method.
        byte[] responseArray = myWebClient.UploadFile(uriString, fileName);

        // Decode and display the response.
        Console.WriteLine("\nResponse Received.The contents of the file uploaded are:\n{0}",
            System.Text.Encoding.ASCII.GetString(responseArray));

2
如果您将证书添加到webRequest.ClientCertificates中,则不再需要覆盖ServerCertificateValidationCallback,该设置是全局的,因此会影响所有内容。 - yoel halb
如果您遇到以下异常信息 The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel,请添加以下代码 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; - Fourat

5
当我们在前端安装了新的证书时,发生了有趣的事情。我们开始收到如下错误消息:
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.; The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."
我们通过打开每个前端浏览器来解决这个错误。似乎IE浏览器缓存了旧的证书。通过打开浏览器,新证书生效了。问题解决了!

4

只需创建WebClient子类,添加自己的ClientCertificates属性并重写WebClient.GetWebRequest(System.Uri)方法即可。我没有时间将此从VB转换为C#,但它应该相当简单明了:

Imports System.Net

Public Class WebClient2
    Inherits System.Net.WebClient

    Private _ClientCertificates As New System.Security.Cryptography.X509Certificates.X509CertificateCollection
    Public ReadOnly Property ClientCertificates() As System.Security.Cryptography.X509Certificates.X509CertificateCollection
        Get
            Return Me._ClientCertificates
        End Get
    End Property
    Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
        Dim R = MyBase.GetWebRequest(address)
        If TypeOf R Is HttpWebRequest Then
            Dim WR = DirectCast(R, HttpWebRequest)
            If Me._ClientCertificates IsNot Nothing AndAlso Me._ClientCertificates.Count > 0 Then
                WR.ClientCertificates.AddRange(Me._ClientCertificates)
            End If
        End If
        Return R
    End Function
End Class

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接