1、阿里云短信服务
该服务基于阿里云短信服务平台OpenAPI门户-短信服务-短信发送-发送短信(SendSms)进行开发,已验证,可发送,包含了所有的校验、签名算法。
SendSms_短信服务_API文档-阿里云OpenAPI开发者门户 (aliyun.com)
2、aliyunmsg_service.h(头文件)
#ifndef GATEWAYCONFIGEMBED_ALIYUNMSG_SERVICE_H
#define GATEWAYCONFIGEMBED_ALIYUNMSG_SERVICE_H
#include "../../web/common/common.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include "../../web/httpserver/mongoose.h"
#include <ctime>
#include <string>
#include <iostream>
string percentEncode(const std::string& str);
string sha256Hex(const std::string& str);
string hmacSha256(const std::string& key, const std::string& data);
string generateRandomUUID();
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);
string generateTimestamp();
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 <ctime>
#include <iostream>
#include <iomanip>
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;
}
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();
}
// Callback function to handle response from server
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
std::cout << "Response: " << std::string(hm->message.ptr, hm->message.len) << std::endl;
*(bool *) fn_data = true; // Mark response as received
}
}
// 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 using Mongoose
struct mg_mgr mgr;
struct mg_connection *nc;
bool done = false;
mg_mgr_init(&mgr);
nc = mg_http_connect(&mgr, url.c_str(), ev_handler, &done);
if (nc != NULL) {
// Add headers
mg_printf(nc, "POST /?%s HTTP/1.1\r\n", queryString.c_str());
for (const auto& header : headers) {
mg_printf(nc, "%s: %s\r\n", header.first.c_str(), header.second.c_str());
}
mg_printf(nc, "Content-Length: %d\r\n\r\n%s", (int)requestBody.length(), requestBody.c_str());
// Wait for the response
while (!done) {
mg_mgr_poll(&mgr, 1000);
}
} else {
std::cerr << "Failed to connect to " << url << std::endl;
}
mg_mgr_free(&mgr);
}
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);