Libcurl的編譯_HTTP/HTTPS客戶端原始碼示例
HTTP/HTTPS客戶端原始碼示例
環境: zlib-1.2.8 openssl-1.0.1g curl-7.36
Author: Kagula
LastUpdateDate: 2016-05-09
閱讀前提:CMake工具的基本使用、配置openssl-1.0.1g 開發環境
編譯zlib庫
下載zlib-1.2.8.tar.gz並解壓縮到" D:\SDK\zlib-1.2.8",使用CMake工具生成zlib.sln,在Visual Studio2013中開啟並編譯即可。
編譯curl-7.36.0
假設Open SSL已經安裝到“D:\SDK\openssl-1.0.1g”,先設定下面的環境變數
OPENSSL_LIBRARIES=D:\SDK\openssl-1.0.1g\out32
OPENSSL_ROOT_DIR=D:\SDK\openssl-1.0.1g
從http://curl.haxx.se/下載curl-7.36.0.zip並解壓縮到“D:\SDK\curl-7.36.0”啟動CMake工具Configure,分別設定LIB_EAY_RELEASE和SSL_EAY_RELEASE變數為“D:\SDK\openssl-1.0.1g\out32\libeay32.lib”,“D:\SDK\openssl-1.0.1g\out32\ssleay32.lib”,產生sln檔案後開啟,為裡面的curl工程專案新增“USE_MANUAL
為專案新增連結庫libcurl_imp.lib , 把libcurl.dll檔案複製到C++專案路徑下,否則程式執行會提示找不到動態連結庫。
下面是HTTP/HTTPS客戶端示例
如何使用
#include <iostream> #include <string> using namespace std; #include "httpclient.h" int main(int argc, char *argv[]) { string response; //login kagula::network::CHttpClient client; int nR = client.Post("https://lijun:8443/escortcashbox/main/login.do", "data={\"version\":\"1.0.0.0\",\"user\":\"admin\",\"password\":\"123\"}", response,true, "d:\cookie.txt", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem", "123456"); cout << nR << endl <<response << endl; //upload png file /* std::map<std::string,std::string> mapFields; std::map<std::string,std::vector<std::string>> mapFiles; mapFields["data"] = "{\"version\":\"1.0.0.0\",\"socialid\":\"1012\",\"realname\":\"realnamevalue\",\"portrait\":\"protraitvalue\",\"fingerid\":\"fingeridvalue\",\"groupid\":\"123\"}"; std::vector<std::string> vecFile(2); vecFile[0] = "d:\\b.png"; vecFile[1] = "image/png"; mapFiles["portraitFile"] = vecFile; nR = client.MultipartFormdata("https://lijun:8443/escortcashbox/main/escortStaffAdd.do", mapFields,mapFiles, response, "d:\cookie.txt", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem", "123456"); cout << nR << endl << response << endl; */ //download png file nR = client.GetFile("https://lijun:8443/escortcashbox/upload/img/20160527_110514_679_426.png", "d:/ee.png", "d:\cookie.txt", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/tomcat7.pem", "D:/workspace_qt/build-escortcashbox_c-Mingw32-Debug/debug/client_all.pem", "123456"); cout << nR << endl; return 0; }
HttpClient.h封裝好的標頭檔案
//HttpClient.h原始碼清單
#ifndef _HTTPCLIENT_H_
#define _HTTPCLIENT_H_
#include <string>
#include <map>
#include <vector>
/*
Title: Get Response from Web Server by HTTP/HTTPS method.
Environment:
Windows 7SP1, Windows 8.1, Windows 10
QT Creator 3.5.1, Visual Studio 2013 Update1, Visual Studio 2013 Update5
libcurl 7.36.0, libcurl 7.46.0, Qt 5.6, MSYS2 64bits gcc 5.3.0
Last Update: 2016-05-27
Remark:
[1]如果要在多執行緒方式下同時呼叫多個CHttpClient例項,
需要在App初始化的時候呼叫kagula::network::Init();
在App結束的時候呼叫kagula::network::Cleanup();
[2]編譯libcurl必須開啟zlib標誌,並且把OpenSSL也鏈進去。
Reference:
curl_eay_setopt manual
http://www.helplib.net/s/linux.die/65_2740/man-3-curl-easy-setopt.shtml
C++ cout format
http://www.cnblogs.com/devymex/archive/2010/09/06/1818754.html
*/
namespace kagula
{
namespace network
{
void Init();
void Cleanup();
class CHttpClient
{
public:
CHttpClient(void);
~CHttpClient(void);
public:
/**
* @brief HTTP/HTTPS POST/GET請求
* @param strUrl 輸入引數,請求的Url地址,如:https://www.alipay.com
* @param strPost 輸入引數,使用如下格式para1=val1¶2=val2&…
* @param strCookie 輸入引數,Cookie檔名,例如 d:\temp\cookie.txt
* 如果為空,不啟用Cookie.
* @param strResponse 輸出引數,返回的內容
* @param bPost 是否Post方式傳送請求,預設Post方式傳送請求。
* @param pCaPath 輸入引數,為CA證書的路徑.如果輸入為NULL,則不驗證伺服器端證書的有效性.
* @param pClientCalPath 輸入引數,為客戶端證書的路徑.如果輸入為NULL,則不驗證客戶端證書的有效性.
* @param pClientCalPassword 輸入引數,為客戶端證書的存取密碼.
* @return 返回是否Post成功
* 0 成功
* 7 無法連線
* 28 超時
* 58 服務端驗證客戶端證書失敗。
* 60 客戶端驗證服務端證書失敗。
*/
int Post(const char* pUrl,
const char* pPost,
std::string &strResponse,
bool bPost,
const char* pCookie,
const char* pCaPath = NULL,
const char* pClientCalPath = NULL,
const char* pClientCalPassword = NULL);
int MultipartFormdata(const char *pUrl,
const std::map<std::string,std::string> & mapFields,
const std::map<std::string,std::vector<std::string>> & mapFiles,
std::string & strResponse,
const char *pCookie,
const char * pCaPath = NULL,
const char * pClientCalPath = NULL,
const char * pClientCalPassword = NULL);
int GetFile(const char* pUrl,
const char* pLocalFullPath,
const char* pCookie,
const char* pCaPath = NULL,
const char* pClientCalPath = NULL,
const char* pClientCalPassword = NULL);
public:
void SetDebug(bool bDebug);
std::string getMsgInChinese(int code);
private:
bool m_bDebug;
bool PrintCookies(void* curl, std::string& strOut);
};
}
}
#endif
原始檔清單
//HttpClient.cpp原始碼清單
#include "HttpClient.h"
#include <iostream>
#include <curl/curl.h>
#include <iomanip>
#include <sstream>
#ifdef WIN32
#pragma comment(lib,"libcurl_imp.lib")
#endif
namespace kagula
{
namespace network
{
CHttpClient::CHttpClient(void) :
m_bDebug(false)
{
}
CHttpClient::~CHttpClient(void)
{
}
bool CHttpClient::PrintCookies(void* curl, std::string& strOut)
{
std::ostringstream ostr;
CURLcode res;
struct curl_slist *cookies;
res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
if (res != CURLE_OK) {
ostr << "Curl curl_easy_getinfo failed:" << curl_easy_strerror(res) << std::endl;
strOut = ostr.str();
return false;
}
const struct curl_slist *nc = cookies;
int i = 1;
ostr << "Cookies, curl knows:" << std::endl;
while (nc) {
ostr << "[" << i++ << "]: " << nc->data << std::endl;
nc = nc->next;
}
return true;
}
static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *)
{
if (itype == CURLINFO_TEXT)
{
//printf("[TEXT]%s\n", pData);
}
else if (itype == CURLINFO_HEADER_IN)
{
printf("[HEADER_IN]%s\n", pData);
}
else if (itype == CURLINFO_HEADER_OUT)
{
printf("[HEADER_OUT]%s\n", pData);
}
else if (itype == CURLINFO_DATA_IN)
{
printf("[DATA_IN]%s\n", pData);
}
else if (itype == CURLINFO_DATA_OUT)
{
printf("[DATA_OUT]%s\n", pData);
}
return 0;
}
size_t OnWriteData_Post(void* buffer, size_t size, size_t nmemb, void* lpVoid)
{
std::string* str = reinterpret_cast<std::string*>(lpVoid);
if (NULL == str || NULL == buffer)
{
return -1;
}
char* pData = reinterpret_cast<char*>(buffer);
str->append(pData, size * nmemb);
return nmemb;
}
size_t OnWriteData_MultipartFormdata( void *inBuffer, size_t size, size_t nmemb, void *outBuffer )
{
int len = size * nmemb;
char *temp = new char[len+1];
memcpy(temp,inBuffer,len);
temp[len]=0;
reinterpret_cast<std::string *>(outBuffer)->append(temp);
delete temp;
return len;
}
size_t OnWriteData_GetFile(void *inBuffer, int size, int nmemb, std::string &content)
{
long len = size * nmemb;
std::string temp((char *)inBuffer, len);
content += temp;
return len;
}
std::string CHttpClient::getMsgInChinese(int code)
{
switch(code)
{
case 0:
return "通訊成功";
case 7:
return "伺服器連線失敗。";
case 28:
return "連線超時。";
case 58:
return "服務端驗證客戶端證書失敗。";
case 60:
return "客戶端驗證服務端證書失敗。";
default:
return "";
}
}
int CHttpClient::Post(const char* pUrl,
const char* pPost,
std::string & strResponse,
bool bPost,
const char* pCookie,
const char* pCaPath,
const char* pClientCalPath,
const char* pClientCalPassword)
{
strResponse = "";
CURLcode res;
CURL* curl = curl_easy_init();
if (NULL == curl)
{
return CURLE_FAILED_INIT;
}
if (m_bDebug)
{
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug);
}
curl_easy_setopt(curl, CURLOPT_URL, pUrl);
if(bPost)
{
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, pPost);
}
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_Post);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
}
if (NULL == pCaPath)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
//需要在編譯curl的時候,一同編譯zlib標誌。要不然找不到這個標誌.
//當然前提是你已經編譯完成zlib.
//發出接受gzip壓縮內容的請求,如果伺服器支援gzip內容,會返回壓縮後的資料。
//如果Http伺服器不支援gzip encoding也不影響libcurl正常工作。
//接受資料的時候,如果返回的是壓縮資料,libcurl會自動解壓資料。
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
}
else
{
//預設情況就是PEM,所以無需設定,另外支援DER
//curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
//服務端需要認證客戶端的真實性,即雙向認證。
if(pClientCalPath!=NULL)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
}
}
//
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);
//Web伺服器一般會重定向連結,比如訪問http:/xxx/x1.do自動轉到http:/xxx/x2.do
//所以一定要設定CURLOPT_FOLLOWLOCATION為1,否則重定向後的資料不會返回。
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,1);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return res;
}
int CHttpClient::MultipartFormdata(const char *pUrl,
const std::map<std::string,std::string> & mapFields,
const std::map<std::string,std::vector<std::string>> & mapFiles,
std::string & strResponse,
const char *pCookie,const char * pCaPath,
const char * pClientCalPath,const char * pClientCalPassword)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
strResponse ="";
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_MultipartFormdata);//write_data
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &strResponse);
struct curl_httppost *formpost = 0;
struct curl_httppost *lastptr = 0;
//
std::map<std::string,std::string>::const_iterator iterFields = mapFields.begin();
while(iterFields!=mapFields.end())
{
//curl_formadd(&formpost, &lastptr,CURLFORM_COPYNAME,"data",CURLFORM_COPYCONTENTS, pData,CURLFORM_END);
curl_formadd(&formpost, &lastptr,CURLFORM_COPYNAME,iterFields->first.c_str(),
CURLFORM_COPYCONTENTS, iterFields->second.c_str(),CURLFORM_END);
iterFields++;
}
std::map<std::string,std::vector<std::string>>::const_iterator iterFiles = mapFiles.begin();
while(iterFiles!=mapFiles.end())
{
//"image/jpeg","image/png"
//curl_formadd(&formpost, &lastptr,CURLFORM_PTRNAME, "portraitFile", CURLFORM_FILE, pImageFileName,CURLFORM_CONTENTTYPE, "image/png", CURLFORM_END);
curl_formadd(&formpost, &lastptr,CURLFORM_PTRNAME,
iterFiles->first.c_str(), CURLFORM_FILE,
iterFiles->second[0].c_str(),CURLFORM_CONTENTTYPE,
iterFiles->second[1].c_str(), CURLFORM_END);
iterFiles++;
}
//
curl_easy_setopt(curl, CURLOPT_URL, pUrl);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
}
//單向認證用
if(pCaPath!=0)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
//服務端需要認證客戶端的真實性,即雙向認證。
if(pClientCalPath!=0 && pClientCalPassword!=0)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
}
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_formfree(formpost);
return res;
}
int CHttpClient::GetFile(const char* pUrl,
const char* pLocalFullPath,
const char* pCookie,
const char* pCaPath,
const char* pClientCalPath,
const char* pClientCalPassword)
{
CURL *curl = NULL;
CURLcode code;
char bufError[CURL_ERROR_SIZE];
std::string content;
long retcode = 0;
code = curl_global_init(CURL_GLOBAL_DEFAULT);
if (code != CURLE_OK)
{
//printf("Failed to global init default [%d]\n", code);
return -100;
}
curl = curl_easy_init();
if (curl == NULL)
{
//printf("Failed to create CURL connection\n");
return -200;
}
code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, bufError);
if (code != CURLE_OK)
{
//printf("Failed to set error buffer [%d]\n", code);
return code;
}
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
code = curl_easy_setopt(curl, CURLOPT_URL, pUrl);
if (code != CURLE_OK)
{
//printf("Failed to set URL [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
if (code != CURLE_OK)
{
//printf("Failed to set redirect option [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData_GetFile);
if (code != CURLE_OK)
{
//printf("Failed to set writer [%s]\n", error);
goto _END;
}
code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &content);
if (code != CURLE_OK)
{
//printf("Failed to set write data [%s]\n", error);
goto _END;
}
if (pCookie!=0)
{
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, (void *)pCookie);
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, (void *)pCookie);
}
//單向認證用
if(pCaPath!=0)
{
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true);
curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath);
}
//服務端需要認證客戶端的真實性,即雙向認證。
if(pClientCalPath!=0 && pClientCalPassword!=0)
{
curl_easy_setopt(curl,CURLOPT_SSLCERT, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLCERTPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(curl,CURLOPT_SSLKEY, pClientCalPath);
curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD, pClientCalPassword);
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE, "PEM");
}
code = curl_easy_perform(curl);
if (code != CURLE_OK)
{
//printf("Failed to get '%s' [%s]\n", URL, error);
goto _END;
}
code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &retcode);
if ((code == CURLE_OK) && retcode == 200)
{
double length = 0;
code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &length);
//printf("%d", retcode);
FILE * file = fopen(pLocalFullPath, "wb");
fseek(file, 0, SEEK_SET);
fwrite(content.c_str(), 1, (size_t)length, file);
fclose(file);
code = CURLE_OK;
goto _END;
}
_END:
curl_easy_cleanup(curl);
return code;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void CHttpClient::SetDebug(bool bDebug)
{
m_bDebug = bDebug;
}
void Init()
{
//the function is not thread safe.
curl_global_init(CURL_GLOBAL_ALL);
}
void Cleanup()
{
curl_global_cleanup();
}
}
}
注意:
[1]MSys64 Mingw32 QtCreator 32位C++程式 配置libcurl
假設Msys64是安裝在C盤預設路徑上
第一步:在Msys64中查詢可用的curl包
pacman -Ss curl
第二步:安裝
pacman -S mingw-w64-i686-curl
第三步:在.pro檔案下加入下面的程式碼
LIBS += C:\msys64\mingw32\lib\libcurl.dll.a
INCLUDEPATH += C:\msys64\mingw32\include
最後:編譯連結依賴libcurl的專案成功。
[2]如何產生cer檔案
https原理及tomcat配置https方法
http://jingyan.baidu.com/article/a948d6515d3e850a2dcd2ee6.html
[3]單向認證,讓客戶端信任服務端證書
第一步:
雙擊從服務端keystore中匯出的cer檔案可以匯入證書。
windows下“certmgr.msc”命令可以進入證書管理。
自己製作的證書匯入到Win7後預設在“中級證書頒發機構”->“證書”節點裡。
第二步:
需要把你做的證書拖到“受信任的根證書頒發機構”->“證書”節點中去,否則
瀏覽器會提醒“此網站出具的安全證書不是由受信任的證書頒發機構頒發的”等類似錯誤。
chrome需要重啟,IE直接重新整理頁面,就不會出現警告了。
注意:
數字證書轉換cer---pem
在Msys2 Shell中確保安裝好openssl.
在Msys2 Shell中使用openssl命令後進入openssl提示符,輸入下面的命令
x509 -inform der -in d:/MyServerSecurity/tomcat7.cer -out d:/MyServerSecurity/tomcat7.pem
[4]雙向認證,讓服務端信任客戶端的證書
相當於“Https單向認證”,添加了“服務端驗證客戶端身份真實性”的動作。
需要注意的是:服務端的金鑰庫引數“CN”必須與服務端的IP地址相同,否則會報錯,客戶端的任意。
如果服務端的CN為lijun,則客戶端不能為lijun,即這兩個不能是同一個名字。
第一步:客戶端生成證書(用於服務端驗證客戶端)
keytool -validity 365 -genkeypair -v -alias kagula -keyalg RSA -storetype PKCS12 -keystore D:\MyClientSecurity\kagulakey.p12 -storepass 123456 -keypass 123456
kagula為證書的名稱,D:\MyClientSecurity\kagulakey.p12證書的存放位置。
第二步:證書格式轉為cer檔案。
keytool -export -v -alias kagula -keystore D:\MyClientSecurity\kagulakey.p12 -storetype PKCS12 -storepass 123456 -rfc -file D:\MyClientSecurity\kagulakey.cer
kagula為證書的名稱,D:\MyClientSecurity\kagulakey.p12證書的存放位置,123456證書密碼,D:\MyClientSecurity\kagulakey.cer匯出的檔案。
第三步:新增到(或新建)一個keystore檔案
keytool -import -v -alias kagula -file D:\MyClientSecurity\kagulakey.cer -keystore D:\MyServerSecurity\tomcat7_client.keystore -storepass 123456
tomcat7_client.keystore如果不存在就會新建一個keystore,如果存在會新增到已經存在的keystore中。
第四步:檢視keystore檔案中的內容
keytool -list -keystore D:\MyServerSecurity\tomcat7_client.keystore
第五步:修改tomcat7中的server.xml檔案
原單向認證的配置如下
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="D:\\MyServerSecurity\\tomcat7.keystore" keystorePass="123456"/>
現在修改後,如下
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="true" sslProtocol="TLS"
keystoreFile="D:\\MyServerSecurity\\tomcat7.keystore" keystorePass="123456"
truststoreFile="D:\\MyServerSecurity\\tomcat7_client.keystore" truststorePass="123456"/>
添加了最後一行屬性使它指向客戶端證書,並把clientAuth屬性從false改為true。
第六步(可選):
Step6-1:
測試Windows下的Chrome是否還能訪問伺服器,果然重新整理瀏覽器後
“https://lijun:8443/escortcashbox/main/aboutUs.do”返回錯誤資訊
Step6-2:
測試libcurl是否還能訪問伺服器,現在libcurl返回7(無法連線伺服器)的錯誤資訊。
最後一步-讓Windows下的Chrome和IE能訪問服務端:
雙擊D:\MyClientSecurity\kagulakey.p12檔案,“不需要新增到受信任的根證書機構”結點,直接匯入證書即可。
預設在certmgr.msc命令,“個人”->“證書”節點下。
最後一步-讓libcurl能訪問服務端:
使用msys64開啟openssl命令列工具
#客戶端個人證書的公鑰
openssl>pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_publickey.pem -nokeys
也許如果在當前command shell下能找到openssl.exe也可以用下面的命令
“openssl pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_publickey.pem -nokeys”
#客戶端個人證書的私鑰
openssl pkcs12 -in D:\MyClientSecurity\myclientkey.p12 -out D:\MyClientSecurity\client_privatekey.pem -nocerts -nodes
#也可以轉換為公鑰與私鑰合二為一的檔案; 客戶端公鑰與私鑰,一起存在all.pem中
openssl>pkcs12 -in D:\MyClientSecurity\kagulakey.p12 -out D:\MyClientSecurity\client_all.pem -nodes
1、使用client_publickey.pem + client_privatekey.pem (未在win console shell下測試)
curl -k --cert client_publickey.pem --key D:\MyClientSecurity\client_privatekey.pem https://lijun:8443/escortcashbox/main/aboutUs.do
2、可以在Msys64 Shell中執行curl命令(如果已經安裝了curl)...使用all.pem
curl -k --cert /d/MyClientSecurity/client_all.pem https://lijun:8443/escortcashbox/main/aboutUs.do
下面是雙向認證的參考資料
SSL——Secure Sockets Layer
http://www.blogjava.net/icewee/archive/2012/06/04/379947.html
補充閱讀資料
使用libcurl實現上傳檔案到FTP伺服器
http://blog.csdn.net/lee353086/article/details/5823145
使用libcurl下載http://www.baidu.com/img/baidu.gif示例
http://www.cppblog.com/qiujian5628/archive/2008/06/28/54873.html
libcurl的使用總結(一)
http://www.vimer.cn/2010/03/libcurl%E7%9A%84%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93%EF%BC%88%E4%B8%80%EF%BC%89.html
PHP的curl實現get,post 和 cookie
http://www.tsingpost.com/articles/201403/525.html