C++用winhttp实现https访问服务器

        由于项目升级,在数据传输过程中需要经过OAuth2.0认证,访问服务器需要https协议。

        首先,实现C++代码访问https 服务器,实现Get和post功能,在网上搜索一通,发现各种各样的都有,有的很简单,有的稍微复杂。结果MSDN介绍的比较简洁一点

        官方网址:https://docs.microsoft.com/en-us/windows/desktop/WinHttp/ssl-in-winhttp

        网友翻译:https://blog.csdn.net/edger2heaven/article/details/45664297

        我们的要求还是相对比较简单,OAuth 采用客户端模式(client credentials)

        参考阮一峰blog

        http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html

 

客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。

客户端模式

它的步骤如下:

(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

(B)认证服务器确认无误后,向客户端提供访问令牌。

A步骤中,客户端发出的HTTP请求,包含以下参数:

  • granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
  • scope:表示权限范围,可选项。

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=client_credentials

认证服务器必须以某种方式,验证客户端身份。

B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。


     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "example_parameter":"example_value"
     }

 

以下是POST的代码,代码有点瑕疵,不能通用于普通项目,但是流程是通用的。

GET的代码也是大同小异,只是https头部信息有所不用

#include "stdafx.h"
#include "windows.h"
#include "winhttp.h"
#include "wchar.h"
#include "wincrypt.h"
#include <comdef.h>

#pragma comment(lib, "Winhttp.lib")
#pragma comment(lib, "Crypt32.lib")

wstring string2wstring(const string &str)
{
    _bstr_t tmp = str.c_str();
    wchar_t* pwchar  = (wchar_t*)tmp;
    wstring ret = pwchar;
    return ret;
}

void winhttp_client_post(){

LPSTR pszData = "WinHttpWriteData Example";
DWORD dwBytesWritten = 0;
BOOL  bResults = FALSE;
HINTERNET hSession = NULL,
          hConnect = NULL,
          hRequest = NULL;

			

// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(  L"A WinHTTP Example Program/1.0", 
                         WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                         WINHTTP_NO_PROXY_NAME, 
                         WINHTTP_NO_PROXY_BYPASS, 0);

// Specify an HTTP server.
if (hSession)
    hConnect = WinHttpConnect( hSession, L"www.wingtiptoys.com",
                               INTERNET_DEFAULT_HTTPS_PORT, 0);

// Create an HTTP Request handle.
if (hConnect)
    hRequest = WinHttpOpenRequest( hConnect, L"POST", 
                                   L"/token", 
                                   NULL, WINHTTP_NO_REFERER, 
                                   WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                   0);

// Set HTTP Options
DWORD dwTimeOut = 3000;
DWORD dwFlags =SECURITY_FLAG_IGNORE_UNKNOWN_CA |
                SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
                SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
                SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;

BOOL bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_CONNECT_TIMEOUT, &dwTimeOut, sizeof(DWORD));
bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &dwFlags, sizeof(dwFlags));
bRet = WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);

//加上OAuth认证需要的header信息:
std::string client_id = "test client id";
std::string client_secure = "test client security";
// client id and secure need base64 encode
std::wstring strHeader = L"Content-type:application/x-www-form-urlencoded\r\n";
strHeader += L"Authorization: Basic ";
//strHeader += string2wstring(tmsstring) +L"\r\n"; //tmsstring is client and secure after base64 encoding

bRet = WinHttpAddRequestHeader(hRequest, strHeader.c_str(), strHeader.length(), WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_REPLACE);
// Send a Request.

std::string strTmp = "grant_type=client_credentials"; //OAuth认证模式是客户端模式
if (hRequest) 
    bResults = WinHttpSendRequest( hRequest, 
                                   WINHTTP_NO_ADDITIONAL_HEADERS,
                                   0, (LPVOID)strTmp.c_str(), strTmp.length(), 
                                   strTmp.length(), 0);

// Write data to the server. don't need this step
/*if (bResults)
    bResults = WinHttpWriteData( hRequest, pszData, 
                                 (DWORD)strlen(pszData), 
                                 &amp;dwBytesWritten);
*/
// End the request.
if (bResults)
    bResults = WinHttpReceiveResponse( hRequest, NULL);

// Report any errors.
if (!bResults)
    printf("Error %d has occurred.\n",GetLastError());

//接收服务器返回数据
if(bRet)
{
    char *pszOutBuf;
    DWORD dwSize = 0;
    DWORD dwDownLoaded = 0;
    std::string strJson; //返回的是Json格式
    
    do
     {
        if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
            {
                //error log
            }
        pszOutBuf = new char[dwSize+1];
        ZeroMemory(pszOutBuf, dwSize+1);

        if  (!WinHttpReadData( hRequest, (LPVOID)pszOutBuf, dwSize, &dwDownLoaded) )
            {
                //error log
            }

        strJson += pszOutBuf;
     }while(dwSize > 0);
}


// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);

}

 

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是使用 WinHTTP 在 Qt 中进行 HTTPS 请求的示例代码: ```cpp #include <QCoreApplication> #include <QUrl> #include <QDebug> #include <QByteArray> #include <Windows.h> #include <winhttp.h> #pragma comment(lib,"winhttp.lib") int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建 WinHTTP 会话 HINTERNET hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_SECURE); if (!hSession) { qDebug() << "WinHttpOpen failed: " << GetLastError(); return -1; } // 创建 HTTP 连接 QUrl url("https://www.example.com"); HINTERNET hConnect = WinHttpConnect(hSession, reinterpret_cast<const wchar_t*>(url.host().utf16()), url.port() == -1 ? INTERNET_DEFAULT_HTTPS_PORT : url.port(), 0); if (!hConnect) { WinHttpCloseHandle(hSession); qDebug() << "WinHttpConnect failed: " << GetLastError(); return -1; } // 创建 HTTP 请求 HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", reinterpret_cast<const wchar_t*>(url.path().utf16()), L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); if (!hRequest) { WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); qDebug() << "WinHttpOpenRequest failed: " << GetLastError(); return -1; } // 发送 HTTP 请求 if (!WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); qDebug() << "WinHttpSendRequest failed: " << GetLastError(); return -1; } // 等待响应 if (!WinHttpReceiveResponse(hRequest, 0)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); qDebug() << "WinHttpReceiveResponse failed: " << GetLastError(); return -1; } // 读取响应数据 QByteArray responseData; DWORD dwSize = 0; do { char szData[1024] = { 0 }; if (!WinHttpReadData(hRequest, szData, sizeof(szData) - 1, &dwSize)) { WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); qDebug() << "WinHttpReadData failed: " << GetLastError(); return -1; } responseData.append(szData, static_cast<int>(dwSize)); } while (dwSize > 0); // 输出响应数据 qDebug() << responseData; // 关闭 WinHTTP 相关句柄 WinHttpCloseHandle(hRequest); WinHttpCloseHandle(hConnect); WinHttpCloseHandle(hSession); return a.exec(); } ``` 在这个示例中,我们增加了一个 `WINHTTP_FLAG_SECURE` 标志来打开安全连接。请注意,在使用 HTTPS 请求时,我们需要确保我们使用的证书是受信任的,否则 WinHTTP 将无法建立安全连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值