有没有办法使用FtpWebRequest使用C#中的客户端证书对FTP进行身份validation?

我正在尝试将文件上传到FTP服务器,我需要使用客户端证书进行身份validation,而不是用户名和密码。

var fullFtpPath = String.Concat(ftpItem.FtpAddress, "/", record, ".txt"); FtpWebRequest request = (FtpWebRequest) WebRequest.Create(fullFtpPath); request.Credentials = new NetworkCredential(ftpItem.Username, ftpItem.Password); request.Method = WebRequestMethods.Ftp.UploadFile; request.UseBinary = true; request.UsePassive = ftpItem.UsePassive; request.EnableSsl = ftpItem.UseSSL; request.ContentLength = bytes.Length; using(Stream s = request.GetRequestStream()) { s.Write(bytes, 0, bytes.Length); } FtpWebResponse response = (FtpWebResponse) request.GetResponse(); Debug.WriteLine("Upload File Complete, status {0}", response.StatusDescription); db.LogExport(siteId, fullFtpPath, record, true, response.StatusDescription); response.Close(); 

以上是我当前的代码,但我不确定如何实现证书身份validation或甚至可以执行它。 我必须创建证书吗? 或者服务器将为我提供证书,我将在我的请求中设置它?

  • 使用FtpWebRequest.ClientCertificates属性指定用于身份validation的证书
  • 证书的类型为X509Certificate
  • 您可以自己构建证书(从字节数组或从文件导入),也可以在证书存储区中查找( X509Store
 FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.example.com"); request.Credentials = new NetworkCredential("username", ""); // Query certificate from store X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); store.Open(OpenFlags.ReadOnly); const string tp = "2b6f8ac51a85cbaf429474a55304313968667611"; X509Certificate2 cert2 = store.Certificates.Find(X509FindType.FindByThumbprint, tp, true)[0]; store.Close(); // Add certificate into request request.ClientCertificates.Add(cert2); 

您可以使用ComponentPro 。 此代码示例说明如何使用证书对客户端进行身份validation:

 using System; using System.Security.Cryptography.X509Certificates; using ComponentPro.Net; ... public void HandleCertificateRequiredEvent() { // Create a new instance. Ftp client = new Ftp(); client.CertificateRequired += client_CertificateRequired; // Connect to the FTP server. client.Connect("myserver", 21, FtpSecurityMode.Explicit); // Authenticate. client.Authenticate("userName", "password"); // Do something here... client.DownloadFile("/my remote file.dat", "my local file"); // Disconnect. client.Disconnect(); } void client_CertificateRequired(object sender, ComponentPro.Security.CertificateRequiredEventArgs e) { // Load certificates from the local machine. X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser); my.Open(OpenFlags.ReadOnly); // Retrieve a list of available certificates. X509Certificate2Collection certs = my.Certificates; // If no certificate found, return. if (certs.Count == 0) { e.Certificates = null; return; } // Show all certificates. Console.WriteLine("Select certificate:"); for (int i = 0; i <= certs.Count; i++) { if (i == 0) { Console.WriteLine(string.Format("{0}. [Nothing, skip this step]", i)); continue; } Console.WriteLine(string.Format("{0}. {1}", i, certs[i - 1].SubjectName.Name)); } // And ask user to choose an appropriate certificate. while (true) { Console.Write(string.Format("Select certificate [0 - {0}]: ", certs.Count)); int certIndex; try { certIndex = int.Parse(Console.ReadLine()); } catch { Console.WriteLine("ERROR: Wrong certificate index input!"); continue; } if (certIndex > 0 && certIndex <= certs.Count) { e.Certificates = new X509Certificate2Collection(certs[certIndex]); return; } if (certIndex == 0) break; Console.WriteLine(string.Format("ERROR: You must enter number between 0 and {0}.", certs.Count)); } } 

ComponentPro也适用于FtpWebRequest :

 using System; using System.IO; using System.Net; ... // Register FtpWebRequest for the specified schema. WebRequest.RegisterPrefix("ftp://", ComponentPro.Net.FtpWebRequest.Creator); Console.WriteLine("Sending request..."); // Create a WebRequest for the specified URL. WebRequest request = WebRequest.Create("ftp://ftp.example.net/pub/myfile.zip"); // Send the WebRequest and waits for a response. WebResponse response = request.GetResponse(); // Get remote file stream for downloading. Stream remoteFileStream = response.GetResponseStream(); Stream localFileStream = File.Create("myfile.zip"); // Create a new buffer to download. byte[] buffer = new byte[1024]; int n; do { // Read data from the remote file stream. n = remoteFileStream.Read(buffer, 0, buffer.Length); // Write to the local file stream. localFileStream.Write(buffer, 0, n); } while (n > 0); Console.WriteLine("Response Received."); localFileStream.Close(); // Release the resources of the response. remoteFileStream.Close();