1、阿里云短信服务
该服务基于阿里云短信服务平台OpenAPI门户-短信服务-短信发送-发送短信(SendSms)进行开发,已验证,可发送,包含了所有的校验、签名算法。
SendSms_短信服务_API文档-阿里云OpenAPI开发者门户 (aliyun.com)
2、aliyunmsg_service.h(头文件)
#ifndef GATEWAYCONFIGEMBED_ALIYUNMSG_SERVICE_H
#define GATEWAYCONFIGEMBED_ALIYUNMSG_SERVICE_H
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <curl/curl.h>
#include <ctime>
#include <string>
#include <iostream>
void sendSms(const std::string& accessKeyId, const std::string& accessSecret, const std::string& phoneNumbers,
const std::string& signName, const std::string& templateCode, const std::string& templateParam, long sendLogId);
#endif //GATEWAYCONFIGEMBED_ALIYUNMSG_SERVICE_H
3、aliyunmsg_service.cpp(源文件)
#include "aliyunmsg_service.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <curl/curl.h>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <map>
std::string percentEncode(const std::string& str) {
std::ostringstream encoded;
for (const auto& c : str) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
encoded << c;
} else if (c == ' ') {
encoded << "%20";
} else if (c == '*') {
encoded << "%2A";
} else {
encoded << '%' << std::uppercase << std::setw(2) << std::setfill('0') << std::hex << (int)(unsigned char)c;
}
}
std::string result = encoded.str();
std::string::size_type pos = 0;
while ((pos = result.find("%7E", pos)) != std::string::npos) {
result.replace(pos, 3, "~");
}
return result;
}
std::string hmacSha256(const std::string& key, const std::string& data) {
unsigned char* digest;
unsigned int digest_len;
digest = HMAC(EVP_sha256(), key.c_str(), key.length(),
(const unsigned char*)data.c_str(), data.length(), NULL, &digest_len);
std::ostringstream ss;
ss << std::hex << std::setfill('0');
for (unsigned int i = 0; i < digest_len; ++i) {
ss << std::setw(2) << (int)digest[i];
}
return ss.str();
}
std::string sha256Hex(const std::string& str) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(str.c_str()), str.length(), hash);
std::ostringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
ss << std::setw(2) << static_cast<int>(hash[i]);
}
return ss.str();
}
std::string generateRandomUUID() {
std::srand(std::time(0));
std::string uuid;
for (int i = 0; i < 16; ++i) {
uuid += "0123456789abcdef"[std::rand() % 16];
}
return uuid;
}
std::string buildCanonicalRequest(const std::string& method, const std::string& uri, const std::string& queryString,
const std::string& canonicalHeaders, const std::string& signedHeaders, const std::string& hashedBody) {
return method + "\n" + uri + "\n" + queryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedBody;
}
std::string generateTimestamp() {
std::time_t rawTime;
std::tm* timeInfo;
std::ostringstream timestampStream;
std::time(&rawTime);
timeInfo = std::gmtime(&rawTime);
timestampStream << std::put_time(timeInfo, "%Y-%m-%dT%H:%M:%SZ");
return timestampStream.str();
}
// Function to send SMS
void sendSms(const std::string& accessKeyId, const std::string& accessSecret, const std::string& phoneNumbers,
const std::string& signName, const std::string& templateCode, const std::string& templateParam, long sendLogId) {
std::string url = "https://dysmsapi.aliyuncs.com/";
std::string host = "dysmsapi.aliyuncs.com";
std::string version = "2017-05-25";
// Step 1: Build query parameters
std::map<std::string, std::string> queryParams = {
{"PhoneNumbers", phoneNumbers},
{"SignName", signName},
{"TemplateCode", templateCode},
{"TemplateParam", templateParam},
{"OutId", std::to_string(sendLogId)}
};
std::string queryString;
for (const auto& param : queryParams) {
if (!queryString.empty()) queryString += "&";
queryString += percentEncode(param.first) + "=" + percentEncode(param.second);
}
std::string timestamp = generateTimestamp();
// Step 2.1: Build headers
std::map<std::string, std::string> headers = {
{"host", host},
{"x-acs-version", version},
{"x-acs-action", "SendSms"},
{"x-acs-date", timestamp},
{"x-acs-signature-nonce", generateRandomUUID()}
};
// Step 2.2: Build canonical headers
std::string canonicalHeaders;
std::string signedHeaders;
for (const auto& header : headers) {
canonicalHeaders += header.first + ":" + header.second + "\n";
signedHeaders += header.first + ";";
}
if (!signedHeaders.empty()) {
signedHeaders.pop_back(); // Remove trailing semicolon
}
// Step 3: Build body and hashed body
std::string requestBody; // Empty for this case
std::string hashedBody = sha256Hex(requestBody);
// Step 4: Build canonical request
std::string canonicalRequest = buildCanonicalRequest("POST", "/", queryString, canonicalHeaders, signedHeaders, hashedBody);
std::string hashedCanonicalRequest = sha256Hex(canonicalRequest);
// Use HMAC-SHA256 to sign the hashed canonical request
std::string stringToSign = "ACS3-HMAC-SHA256\n" + hashedCanonicalRequest;
std::string signature = hmacSha256(accessSecret, stringToSign);
headers["Authorization"] = "ACS3-HMAC-SHA256 Credential=" + accessKeyId + ", SignedHeaders=" + signedHeaders + ", Signature=" + signature;
// Step 5: Send request
CURL* curl = curl_easy_init();
if (curl) {
struct curl_slist* chunk = NULL;
for (const auto& header : headers) {
std::string headerLine = header.first + ": " + header.second;
chunk = curl_slist_append(chunk, headerLine.c_str());
}
curl_easy_setopt(curl, CURLOPT_URL, (url + "?" + queryString).c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}
curl_easy_cleanup(curl);
curl_slist_free_all(chunk);
}
}
4、服务调用
std::string accessKeyId = "xxxxx";
std::string accessSecret = "xxxxx";
std::string phoneNumbers = reinterpret_cast<const char *>(PhoneNumber);
std::string signName = "xxxxx";
std::string templateCode = "xxxxx";
std::string templateParam ="xxxxx";
int OutId=xxx;
sendSms(accessKeyId, accessSecret, phoneNumbers, signName, templateCode,templateParam, OutId);