C# 调用 Https协议web的服务 ssl证书(客户端需要证书)

public class restop
    {
        private string url = "";

        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        private string clientp12path = "";

        public string Clientp12path
        {
            get { return clientp12path; }
            set { clientp12path = value; }
        }
        private string clientp12PassWord = "";

        public string Clientp12PassWord
        {
            get { return clientp12PassWord; }
            set { clientp12PassWord = value; }
        }
        public restop()
        { }
        public string send(string s)
        {
            string retrunstr = "";
            //类似浏览器确认证书合法方法的绑定
            //如果觉得写一个委托方法麻烦,可以直接使用匿名委托
            ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidate;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
            Uri uri = new Uri(@url);
            HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
            byte[] bs = Encoding.UTF8.GetBytes(s);
            //这2句代码表示如果要求客户端证书,将客户端证书加入request,不需要客户端证书的https请求则不需要此代码

//需导入xx.p12证书文件 clientp12path为文件所在路径clientp12password为证书密码

InstallCertificate(clientp12path, clientp12PassWord, StoreLocation.CurrentUser, StoreName.My);
            X509Certificate cer = new X509Certificate(clientp12path, clientp12PassWord);
            request.ClientCertificates.Add(cer);
            request.ContentType = "text/plain";
            request.Method = "post";
            request.KeepAlive = false;
            request.ProtocolVersion = HttpVersion.Version10;
            request.Proxy = null;
            //request.UserAgent = DefaultUserAgent;
            using (Stream reqStram = request.GetRequestStream())
            {
                reqStram.Write(bs, 0, bs.Length);
                reqStram.Close();
            }

            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                retrunstr = reader.ReadToEnd();
            }
            return retrunstr;
        }
        private static bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            // trust any certificate!!!
            //System.Console.WriteLine("Warning, trust any certificate");
            //为了通过证书验证,总是返回true
            return true;
        }
        //导入证书
        public static bool InstallCertificate(string certFilePath, string password, StoreLocation location, StoreName storeName)
        {
            try
            {
                if (!File.Exists(certFilePath))
                {
                    return false;
                }
                byte[] certData = File.ReadAllBytes(certFilePath);
                X509Certificate2 cert = new X509Certificate2(certData, password, X509KeyStorageFlags.Exportable);
                X509Store store = new X509Store(storeName, location);
                store.Open(OpenFlags.MaxAllowed);
                store.Remove(cert);
                store.Add(cert);
                store.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }

 总结:

 由于是首次接触C#调用Https这方面的技术,在网上找了好多资料都说是用以下代码

ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidate;

X509Certificate cer = new X509Certificate(“xx.p12”, "xx");
            request.ClientCertificates.Add(cer);

我总是报以下错误

未处理 System.Net.WebException
  Message=基础连接已经关闭: 发送时发生错误。
  Source=System
  StackTrace:
       在 System.Net.HttpWebRequest.GetResponse()
       在 ConsoleAppRest.restop.send(String s) 位置 E:\大气背景站\https\ConsoleAppRest\ConsoleAppRest\restop.cs:行号 65
       在 ConsoleAppRest.Program.Main(String[] args) 位置 E:\大气背景站\https\ConsoleAppRest\ConsoleAppRest\Program.cs:行号 16
       在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       在 System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.IO.IOException
       Message=由于远程方已关闭传输流,身份验证失败。
       Source=System
       StackTrace:
            在 System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
            在 System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
            在 System.Net.TlsStream.CallProcessAuthentication(Object state)
            在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
            在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
            在 System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
            在 System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
            在 System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
            在 System.Net.ConnectStream.WriteHeaders(Boolean async)
       InnerException: 

找了好久终于找到还是加载证书问题,有人说是的手动导入证书照下面方法导入证书之后程序是能运行了,但太麻烦了你不能让用户去操作这些哇。

操作如下:
1. 单击 开始 ,单击 运行 ,键入 mmc ,然后单击 确定 。
2. 在 文件 菜单上单击 添加/删除管理单元 。
3. 在 添加/删除管理单元 对话框中,单击 添加 。
4. 在 添加独立管理单元 对话框单击 证书 ,然后单击 添加 。
5. 在在 证书管理单元中 对话框中单击 计算机帐户 ,然后单击 下一步
6. 在 选择计算机 对话框中,单击 完成 。
7. 在 添加独立管理单元 对话框单击 关闭 ,然后单击 确定 。
8. 展开 证书 (本地计算机) ,展开 个人 ,然后单击 证书 。
9. 右键 -》 所有任务-》导入 选择你的证书导入
要注意的是:
一定要导入证书+私钥,只导入证书是不行的
即,要导入pfx或者p12文件,而不是导入cer文件

之后在网上又找到程序导入证书的方法

public static bool InstallCertificate(string certFilePath, string password, StoreLocation location, StoreName storeName)
        {
            try
            {
                if (!File.Exists(certFilePath))
                {
                    return false;
                }
                byte[] certData = File.ReadAllBytes(certFilePath);
                X509Certificate2 cert = new X509Certificate2(certData, password, X509KeyStorageFlags.Exportable);
                X509Store store = new X509Store(storeName, location);
                store.Open(OpenFlags.MaxAllowed);
                store.Remove(cert);
                store.Add(cert);
                store.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

问题终于解决了,在这记录一下备忘。

原文地址:https://www.cnblogs.com/asd14828/p/2973278.html