目录

一、阿里云短信服务接口

二、逻辑代码实现

三、编译测试效果


一、阿里云短信服务接口

最近在调用阿里云短信服务接口发现并没有c++的资料,网上查询发现也是零星描述,由于自身项目基础累积了C++的太多,不想掺杂太多语言,就自行实现c++的阿里云短信接口,其难点就在于签名而已,希望能给大家提供参考。

1)我的网页调用接口采用acl_master实现的,acl_master是一个跨平台c/c++库,提供了网络通信库及服务器编程框架,同时提供更多的实用功能库及示例。(下载地址:Github: https://github.com/acl-dev/acl),读者可采用其他库实现。

2)参考阿里云的“HTTP协议及签名”(https://help.aliyun.com/document_detail/56189.html?spm=a2c4g.11186623.6.581.fy2faU)描述文档,先做一些必要的准备:

*注册阿里云,有需要的阿里云产品通用代金券的可以点击下面链接进行领取:

阿里云限量红包

开通短信服务后,在你账户头像下AccessKeys选项进入用户信息管理界面,获取到你的AccessKeyId和AccessKeySecret,具体请参考阿里云短信服务的资料完成操作。

二、逻辑代码实现

*根据"http协议及签名”描述文档,定义了短信请求参数结构,初始化中带*的请自行写入自己实际参数:

struct HttpMsgArg
{HttpMsgArg(): addr_("dysmsapi.aliyuncs.com"), path_(""), port_(80)//, AccessKeyId("********"), AccessKeySecret("***************"), Timestamp("2018-04-13T10:10:10Z"), Format("XML"), SignatureMethod("HMAC-SHA1"), SignatureVersion("1.0"), SignatureNonce("1"), Signature("")//, Action("SendSms"), Version("2017-05-25"), RegionId("cn-hangzhou"), PhoneNumbers("137********"), SignName("短信测试"), TemplateCode("SMS_*******"), TemplateParam(""), SmsUpExtendCode(""), OutId("123"){};//std::string addr_;         // web 服务器地址  std::string path_;            // 本地请求的数据文件  int port_;//std::string AccessKeyId;      //std::string AccessKeySecret;  //std::string Timestamp;            //格式为:yyyy-MM-dd’T’HH:mm:ss’Z’;时区为:GMTstd::string Format;              //没传默认为JSON,可选填值:XMLstd::string SignatureMethod;  //建议固定值:HMAC-SHA1std::string SignatureVersion;   //建议固定值:1.0std::string SignatureNonce;       //用于请求的防重放攻击,每次请求唯一,JAVA语言建议用:java.util.UUID.randomUUID()生成即可std::string Signature;            //最终生成的签名结果值std::string Action;             //API的命名,固定值,如发送短信API的值为:SendSmsstd::string Version;           //API的版本,固定值,如短信API的值为:2017-05-25std::string RegionId;         //API支持的RegionID,如短信API的值为:cn-hangzhou/**短信接收号码,支持以逗号分隔的形式进行批量调用,*批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,*验证码类型的短信推荐使用单条调用的方式*/std::string PhoneNumbers;std::string SignName;           //短信签名std::string TemplateCode;     //短信模板ID/*短信模板变量替换JSON串,友情提示:如果JSON中需要带换行符,请参照标准的JSON协议。*/std::string TemplateParam;std::string SmsUpExtendCode;    //上行短信扩展码,无特殊需要此字段的用户请忽略此字段std::string OutId;               //外部流水扩展字段
};

*url格式转换需求:

unsigned char ToHex(unsigned char x)
{return  x > 9 ? x + 55 : x + 48;
}unsigned char FromHex(unsigned char x)
{unsigned char y;if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;else if (x >= '0' && x <= '9') y = x - '0';else assert(0);return y;
}std::string UrlEncode(const std::string& str)
{std::string strTemp = "";size_t length = str.length();for (size_t i = 0; i < length; i++){if (isalnum((unsigned char)str[i]) ||(str[i] == '-') ||(str[i] == '_') ||(str[i] == '.') ||(str[i] == '~'))strTemp += str[i];else if (str[i] == ' ')strTemp += "+";else{strTemp += '%';strTemp += ToHex((unsigned char)str[i] >> 4);strTemp += ToHex((unsigned char)str[i] % 16);}}return strTemp;
}std::string UrlDecode(const std::string& str)
{std::string strTemp = "";size_t length = str.length();for (size_t i = 0; i < length; i++){if (str[i] == '+') strTemp += ' ';else if (str[i] == '%'){assert(i + 2 < length);unsigned char high = FromHex((unsigned char)str[++i]);unsigned char low = FromHex((unsigned char)str[++i]);strTemp += high * 16 + low;}else strTemp += str[i];}return strTemp;
}

*UUID的生成实现函数:

std::string getUUID() {
#ifdef WIN32char buffer[GUID_LEN] = { 0 };GUID guid;if (CoCreateGuid(&guid)){fprintf(stderr, "create guid error\n");return "";}_snprintf(buffer, sizeof(buffer),"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",guid.Data1, guid.Data2, guid.Data3,guid.Data4[0], guid.Data4[1], guid.Data4[2],guid.Data4[3], guid.Data4[4], guid.Data4[5],guid.Data4[6], guid.Data4[7]);printf("guid: %s\n", buffer);return std::string(buffer);
#elseuuid_t uuid;uuid_generate(uuid);char buf[64] = { 0 };uuid_unparse(uuid, buf);return std::string(buf);
#endif
};

*用于ascii和utf-8的字符格式转换,一些其他的格式转换也一并给出,防止特定需要,主要是阿里参数中文可能需要用到

/hpp
#ifdef WIN32
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#endif#ifndef STRCHANGE_HPP
#define STRCHANGE_HPP#include <string>
#include <vector>#ifdef WIN32
#include <iostream>
#include <windows.h>
#endif//using namespace std;bool containStr(std::string _str, std::string _strsub);#ifdef WIN32
//UTF-8 to Unicode
std::wstring Utf82Unicode(const std::string& utf8string);
//unicode to ascii
std::string WideByte2Acsi(std::wstring& wstrcode);
//ascii to Unicode
std::wstring Acsi2WideByte(std::string& strascii);
//Unicode to Utf8
std::string Unicode2Utf8(const std::wstring& widestring);
#endif#ifdef __linux__
int code_convert(char *from_charset,char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen);
int u2g(char *inbuf,int inlen,char *outbuf,int outlen);
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen);
int u2a(char *inbuf,int inlen,char *outbuf,int outlen);
int a2u(char *inbuf,int inlen,char *outbuf,int outlen);
int u2k(char *inbuf,int inlen,char *outbuf,int outlen);
int k2u(char *inbuf,int inlen,char *outbuf,int outlen);
#endif//utf-8 to ascii
std::string UTF_82ASCII(std::string& strUtf8Code);
//ascii to Utf8
std::string ASCII2UTF_8(std::string& strAsciiCode);#endif //STRCHANGE_HPP/
#include "strchange.h"#include <stdio.h>
#include <stdlib.h>
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#endif
//using namespace std;bool containStr(std::string _str, std::string _strsub)
{std::string::size_type pos = _str.find(_strsub);//if(pos!=std::string::npos){return true;}return false;
};void strToHex16(char *in,unsigned char *out,int size)
{unsigned int ch;int index=0;while(sscanf(in,"%2x",&ch)!=EOF&&index<size){out[index++]=ch;in+=2;}out[index<size?index:(size-1)]='\0';
};void strFromHex16(unsigned char *in,char *out,int size)
{int i=0;while('\0'!=in[i]&&(2*i<size)){//char ch[2]={0};sprintf(out+i*2,"%02x",in[i]);i++;}out[2*i<size?2*i:(size-1)]='\0';
};#ifdef WIN32
//UTF-8 to Unicode
std::wstring Utf82Unicode(const std::string& utf8string)
{int widesize = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, NULL, 0);if (widesize == ERROR_NO_UNICODE_TRANSLATION){throw std::exception("Invalid UTF-8 sequence.");}if (widesize == 0){throw std::exception("Error in conversion.");}std::vector<wchar_t> resultstring(widesize);int convresult = ::MultiByteToWideChar(CP_UTF8, 0, utf8string.c_str(), -1, &resultstring[0], widesize);if (convresult != widesize){throw std::exception("La falla!");}return std::wstring(&resultstring[0]);
};//unicode to asciistd::string WideByte2Acsi(std::wstring& wstrcode)
{int asciisize = ::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, NULL, 0, NULL, NULL);if (asciisize == ERROR_NO_UNICODE_TRANSLATION){throw std::exception("Invalid UTF-8 sequence.");}if (asciisize == 0){throw std::exception("Error in conversion.");}std::vector<char> resultstring(asciisize);int convresult =::WideCharToMultiByte(CP_OEMCP, 0, wstrcode.c_str(), -1, &resultstring[0], asciisize, NULL, NULL);if (convresult != asciisize){throw std::exception("La falla!");}return std::string(&resultstring[0]);
};//cpp///ascii to Unicodestd::wstring Acsi2WideByte(std::string& strascii)
{int widesize = MultiByteToWideChar (CP_ACP, 0, (char*)strascii.c_str(), -1, NULL, 0);if (widesize == ERROR_NO_UNICODE_TRANSLATION){throw std::exception("Invalid UTF-8 sequence.");}if (widesize == 0){throw std::exception("Error in conversion.");}std::vector<wchar_t> resultstring(widesize);int convresult = MultiByteToWideChar (CP_ACP, 0, (char*)strascii.c_str(), -1, &resultstring[0], widesize);if (convresult != widesize){throw std::exception("La falla!");}return std::wstring(&resultstring[0]);
};//Unicode to Utf8std::string Unicode2Utf8(const std::wstring& widestring)
{int utf8size = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, NULL, 0, NULL, NULL);if (utf8size == 0){throw std::exception("Error in conversion.");}std::vector<char> resultstring(utf8size);int convresult = ::WideCharToMultiByte(CP_UTF8, 0, widestring.c_str(), -1, &resultstring[0], utf8size, NULL, NULL);if (convresult != utf8size){throw std::exception("La falla!");}return std::string(&resultstring[0]);
};
#endif#ifdef __linux__
//
int code_convert(char *from_charset,char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{iconv_t cd;//int rc;char **pin = &inbuf;char **pout = &outbuf;cd = iconv_open(to_charset,from_charset);if (cd==0) return -1;memset(outbuf,0,outlen);if (-1==(int)iconv(cd,pin,&inlen,pout,&outlen))return -1;iconv_close(cd);return 0;
}
//
int u2g(char *inbuf,int inlen,char *outbuf,int outlen)
{char _fbuf[32]="utf-8";char _tbuf[32]="gb2312";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}
//
int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen)
{char _fbuf[32]="gb2312";char _tbuf[32]="utf-8";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}int u2a(char *inbuf,int inlen,char *outbuf,int outlen)
{char _fbuf[32]="utf-8";char _tbuf[32]="ascii";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}int a2u(char *inbuf,int inlen,char *outbuf,int outlen)
{char _fbuf[32]="ascii";char _tbuf[32]="utf-8";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}int u2k(char *inbuf,int inlen,char *outbuf,int outlen)
{char _fbuf[32]="utf-8";char _tbuf[32]="gbk";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}int k2u(char *inbuf,int inlen,char *outbuf,int outlen)
{char _fbuf[32]="gbk";char _tbuf[32]="utf-8";return code_convert(_fbuf,_tbuf,inbuf,inlen,outbuf,outlen);
}#endif//utf-8 to asciistd::string UTF_82ASCII(std::string& strUtf8Code)
{#ifdef WIN32std::string strRet("");//std::wstring wstr = Utf82Unicode(strUtf8Code);//strRet = WideByte2Acsi(wstr);return strRet;#endif#ifdef __linux__char lpszBuf[256]={0};u2k(const_cast<char*>(strUtf8Code.c_str()),strUtf8Code.size(),lpszBuf,256);return std::string(lpszBuf);// char lpszBuf[256]={0};// u2a(const_cast<char*>(strUtf8Code.c_str()),strUtf8Code.size(),lpszBuf,256);// return std::string(lpszBuf);// return std::string(strUtf8Code);#endif
};//ascii to Utf8std::string ASCII2UTF_8(std::string& strAsciiCode)
{#ifdef WIN32std::string strRet("");//std::wstring wstr = Acsi2WideByte(strAsciiCode);//strRet = Unicode2Utf8(wstr);return strRet;#endif#ifdef __linux__char lpszBuf[256]={0};k2u(const_cast<char*>(strAsciiCode.c_str()),strAsciiCode.size(),lpszBuf,256);return std::string(lpszBuf);// char lpszBuf[256]={0};// a2u(const_cast<char*>(strAsciiCode.c_str()),strAsciiCode.size(),lpszBuf,256);// return std::string(lpszBuf);// return std::string(strAsciiCode);#endif
};

*阿里云短信接口参数的时间格式要求:

std::string getCurentTimeDesc()
{time_t _t = time(NULL);char bufTime[64] = { 0 };struct tm* _tt;//localtime_s(&_tt, &_t);//系统本地时间_tt = gmtime(&_t);//格林时间_tt->tm_year += 1900;_tt->tm_mon += 1;sprintf(bufTime, "%04d-%02d-%02dT%02d:%02d:%02dZ", _tt->tm_year,_tt->tm_mon,_tt->tm_mday,_tt->tm_hour,_tt->tm_min,_tt->tm_sec);return std::string(bufTime);
}

*重点一签名算法实现,来源网上公开的一些资料,经过实践实用c语言函数

//HMACSHA1.h///
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __HMACSHA1_H__
#define __HMACSHA1_H__typedef unsigned long    __u32;
typedef unsigned char    __u8;typedef struct
{__u32 state[5];__u32 count[2];__u8  buffer[64];
} SHA1_CTX;#if defined(rol)
#undef rol
#endif#define SHA1HANDSOFF#define __LITTLE_ENDIAN #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifdef __LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \|(rol(block->l[i],8)&0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \^block->l[(i+2)&15]^block->l[i&15],1))/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);/* Hash a single 512-bit block. This is the core of the algorithm. */void SHA1Transform(__u32 state[5], __u8 buffer[64]);
void SHA1Init(SHA1_CTX *context);
void SHA1Update(SHA1_CTX *context, unsigned char *data, __u32 len);
void SHA1Final(unsigned char digest[20], SHA1_CTX *context);
//void hmac_sha1(unsigned char *to_mac,unsigned int to_mac_length, unsigned char *key,unsigned int key_length, unsigned char *out_mac);
void hmac_sha
(char* k,    /* 秘钥 secret key */int lk,     /*  秘钥长度 length of the key in bytes */char* d,    /* 数据 data */int ld,     /*  数据长度 length of data in bytes */char* out,  /* 输出的字符串 output buffer, at least "t" bytes */int t
);#endif
///HMACSHA1.cpp///
#include "HMACSHA1.h"#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#ifndef SHA_DIGESTSIZE
#define SHA_DIGESTSIZE 20
#endif#ifndef SHA_BLOCKSIZE
#define SHA_BLOCKSIZE 64
#endif/* Hash a single 512-bit block. This is the core of the algorithm. */void SHA1Transform(__u32 state[5], __u8 buffer[64])
{__u32 a, b, c, d, e;typedef union {unsigned char c[64];__u32 l[16];} CHAR64LONG16;CHAR64LONG16* block;#ifdef SHA1HANDSOFFstatic unsigned char workspace[64];block = (CHAR64LONG16*)workspace;//    NdisMoveMemory(block, buffer, 64);memcpy(block, buffer, 64);
#elseblock = (CHAR64LONG16*)buffer;
#endif/* Copy context->state[] to working vars */a = state[0];b = state[1];c = state[2];d = state[3];e = state[4];/* 4 rounds of 20 operations each. Loop unrolled. */R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3);R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7);R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11);R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15);R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19);R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23);R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27);R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31);R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35);R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39);R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43);R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47);R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51);R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55);R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59);R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63);R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67);R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71);R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75);R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79);/* Add the working vars back into context.state[] */state[0] += a;state[1] += b;state[2] += c;state[3] += d;state[4] += e;/* Wipe variables */a = b = c = d = e = 0;
}/* SHA1Init - Initialize new context */void SHA1Init(SHA1_CTX* context)
{/* SHA1 initialization constants */context->state[0] = 0x67452301;context->state[1] = 0xEFCDAB89;context->state[2] = 0x98BADCFE;context->state[3] = 0x10325476;context->state[4] = 0xC3D2E1F0;context->count[0] = context->count[1] = 0;
}/* Run your data through this. */void SHA1Update(SHA1_CTX* context, unsigned char* data, __u32 len)
{__u32 i, j;j = context->count[0];if ((context->count[0] += len << 3) < j)context->count[1]++;context->count[1] += (len >> 29);j = (j >> 3) & 63;if ((j + len) > 63) {//        NdisMoveMemory(&context->buffer[j], data, (i = 64-j));memcpy(&context->buffer[j], data, (i = 64 - j));SHA1Transform(context->state, context->buffer);for (; i + 63 < len; i += 64) {SHA1Transform(context->state, &data[i]);}j = 0;}else i = 0;//    NdisMoveMemory(&context->buffer[j], &data[i], len - i);memcpy(&context->buffer[j], &data[i], len - i);
}/* Add padding and return the message digest. */void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{__u32 i, j;unsigned char finalcount[8];for (i = 0; i < 8; i++) {finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]>> ((3 - (i & 3)) * 8)) & 255);  /* Endian independent */}SHA1Update(context, (unsigned char *)"\200", 1);while ((context->count[0] & 504) != 448) {SHA1Update(context, (unsigned char *)"\0", 1);}SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */for (i = 0; i < 20; i++) {digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);}/* Wipe variables */i = j = 0;//    NdisZeroMemory(context->buffer, 64);//    NdisZeroMemory(context->state, 20);//    NdisZeroMemory(context->count, 8);//    NdisZeroMemory(&finalcount, 8);memset(context->buffer, 0x00, 64);memset(context->state, 0x00, 20);memset(context->count, 0x00, 8);memset(&finalcount, 0x00, 8);#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite its own static vars */SHA1Transform(context->state, context->buffer);
#endif
}/* Function to print the digest
打印输出*/
void pr_sha(FILE* fp, unsigned char* s, int t)
{int i;for (i = 0; i<t; i++)printf("%02x", s[i]);printf("\n");}void truncate
(char* d1, /* data to be truncated */char* d2, /* truncated data */int len /* length in bytes to keep */
)
{int i;for (i = 0; i < len; i++) d2[i] = d1[i];
}/* Function to compute the digest
加密算法的主要操作函数 */
void hmac_sha
(char* k,    /* 秘钥 secret key */int lk,     /*  秘钥长度 length of the key in bytes */char* d,    /* 数据 data */int ld,     /*  数据长度 length of data in bytes */char* out,  /* 输出的字符串 output buffer, at least "t" bytes */int t
)
{SHA1_CTX ictx, octx;char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE];char key[SHA_DIGESTSIZE];char buf[SHA_BLOCKSIZE];int i;if (lk > SHA_BLOCKSIZE){SHA1_CTX tctx;SHA1Init(&tctx);SHA1Update(&tctx, (unsigned char*)k, lk);SHA1Final((unsigned char*)key, &tctx);k = key;lk = SHA_DIGESTSIZE;}/**** Inner Digest ****/SHA1Init(&ictx);/* Pad the key for inner digest */for (i = 0; i < lk; ++i) buf[i] = k[i] ^ 0x36;for (i = lk; i < SHA_BLOCKSIZE; ++i) buf[i] = 0x36;SHA1Update(&ictx, (unsigned char*)buf, SHA_BLOCKSIZE);SHA1Update(&ictx, (unsigned char*)d, ld);SHA1Final((unsigned char*)isha, &ictx);/**** Outter Digest ****/SHA1Init(&octx);/* Pad the key for outter digest */for (i = 0; i < lk; ++i) buf[i] = k[i] ^ 0x5C;for (i = lk; i < SHA_BLOCKSIZE; ++i) buf[i] = 0x5C;SHA1Update(&octx, (unsigned char*)buf, SHA_BLOCKSIZE);SHA1Update(&octx, (unsigned char*)isha, SHA_DIGESTSIZE);SHA1Final((unsigned char*)osha, &octx);/* truncate and print the results */t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t;truncate(osha, out, t);pr_sha(stdout, (unsigned char*)out, t);}

*重点二Base64算法实现

//ZBase64.h///
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef ___BASE_64_H___
#define ___BASE_64_H___#include <string>class ZBase64
{
public:/*编码DataByte[in]输入的数据长度,以字节为单位*/static std::string Encode(const unsigned char* Data, int DataByte);/*解码DataByte[in]输入的数据长度,以字节为单位OutByte[out]输出的数据长度,以字节为单位,请不要通过返回值计算输出数据的长度*/static std::string Decode(const char* Data, int DataByte, int& OutByte);
};#endif
//ZBase64.cpp/
#include "Base64.h"std::string ZBase64::Encode(const unsigned char* Data, int DataByte)
{//编码表const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";//返回值std::string strEncode;unsigned char Tmp[4] = { 0 };int LineLength = 0;for (int i = 0; i<(int)(DataByte / 3); i++){Tmp[1] = *Data++;Tmp[2] = *Data++;Tmp[3] = *Data++;strEncode += EncodeTable[Tmp[1] >> 2];strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];strEncode += EncodeTable[Tmp[3] & 0x3F];if (LineLength += 4, LineLength == 76) { strEncode += "\r\n"; LineLength = 0; }}//对剩余数据进行编码int Mod = DataByte % 3;if (Mod == 1){Tmp[1] = *Data++;strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];strEncode += "==";}else if (Mod == 2){Tmp[1] = *Data++;Tmp[2] = *Data++;strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];strEncode += "=";}return strEncode;
}std::string ZBase64::Decode(const char* Data, int DataByte, int& OutByte)
{//解码表const char DecodeTable[] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,62, // '+'0, 0, 0,63, // '/'52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'0, 0, 0, 0, 0, 0, 0,0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'0, 0, 0, 0, 0, 0,26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'};//返回值std::string strDecode;int nValue;int i = 0;while (i < DataByte){if (*Data != '\r' && *Data != '\n'){nValue = DecodeTable[*Data++] << 18;nValue += DecodeTable[*Data++] << 12;strDecode += (nValue & 0x00FF0000) >> 16;OutByte++;if (*Data != '='){nValue += DecodeTable[*Data++] << 6;strDecode += (nValue & 0x0000FF00) >> 8;OutByte++;if (*Data != '='){nValue += DecodeTable[*Data++];strDecode += nValue & 0x000000FF;OutByte++;}}i += 4;}else// 回车换行,跳过{Data++;i++;}}return strDecode;
}

3)准备工作完成,开始短信申请全过程,本人借助acl-master库实现,用其他网页访问接口的请斟酌参考

    acl::string aclurl, acladdr;//定义网站、地址aclurl.format("http://%s%s", myArgHttp.addr_.c_str(), myArgHttp.path_.c_str());acladdr.format("%s:%d", myArgHttp.addr_.c_str(), myArgHttp.port_);acl::http_request req(acladdr);//请求构造acl::http_header& header = req.request_header();//访问类型为Getheader.set_method(acl::HTTP_METHOD_GET);header.set_keep_alive(false);//header.accept_gzip(accept_gzip ? true : false);////urlheader.set_url(aclurl);//hostif (header.get_host() == NULL){header.set_host(myArgHttp.addr_.c_str());printf(">>>set host: %s\r\n", myArgHttp.addr_.c_str());}elseprintf(">>>host: %s\r\n", header.get_host());//签名内容缓存std::string sortQueryStringTmp = "";sortQueryStringTmp.append("GET&").append(UrlEncode("/"));//签名内容项,参数key的字符串排序std::string  bufNonce = getUUID();std::string Timestamp = getCurentTimeDesc();myArgHttp.TemplateParam = ASCII2UTF_8(templateParam_);acl::url_coder coder;//注意中文字段UTF-8表述coder.set("AccessKeyId", myArgHttp.AccessKeyId.c_str());coder.set("Action", myArgHttp.Action.c_str());coder.set("Format", myArgHttp.Format.c_str());coder.set("OutId", myArgHttp.OutId.c_str());coder.set("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());coder.set("RegionId", myArgHttp.RegionId.c_str());coder.set("SignName", ASCII2UTF_8(myArgHttp.SignName).c_str());coder.set("SignatureMethod", myArgHttp.SignatureMethod.c_str());coder.set("SignatureNonce", bufNonce.c_str());coder.set("SignatureVersion", myArgHttp.SignatureVersion.c_str());coder.set("TemplateCode", myArgHttp.TemplateCode.c_str());coder.set("TemplateParam", myArgHttp.TemplateParam.c_str());coder.set("Timestamp", Timestamp.c_str());coder.set("Version", myArgHttp.Version.c_str());//std::string urlcode = std::string(coder.to_string().c_str());//printf( "排序参数集:\r\n%s\r\n", urlcode.c_str());sortQueryStringTmp.append("&").append(UrlEncode(urlcode));printf( "待签名的请求字符串UrlEncode:\r\n%s\r\n", sortQueryStringTmp.c_str());//生成签名,调用签名算法函数,注意阿里的AccessKeySecret+&才是真正的AccessKeySecretchar hmac_buf[256] = { 0 };std::string KeySecret_ali = (myArgHttp.AccessKeySecret + "&");hmac_sha((char*)(ASCII2UTF_8(KeySecret_ali)).c_str(), (int)KeySecret_ali.length(), (char*)ASCII2UTF_8(sortQueryStringTmp).c_str(), (int)sortQueryStringTmp.length(), hmac_buf, 20);std::string hmac = std::string(hmac_buf,strlen(hmac_buf));printf( "密钥+HmacSHA1算法:\r\n%s\r\n", hmac.c_str());//base64算法调用,前面签名算法结果作为输入参数,得到最终签名hmac = ZBase64::Encode((const unsigned char*)hmac.c_str(), static_cast<int>(hmac.length()));printf( "HmacSHA1算法+Base64:\r\n%s\r\n", hmac.c_str());//将签名加入请求字段header.add_param("Signature", hmac.c_str());//其他参数加入,注意中文字段UTF-8表述//TemplateParam,例如,"{\"customer\":\"test\"}",//进行传输短信的变量与你阿里短信服务模版的变量一致,(如都存在”customer“变量)//如果模版变量个数在 TemplateParam没有全含括或任意字段不匹配,都无法正常短信发送//变量的描述字段限制20位,例如,test不能超过20个字符长度,否则出错   header.add_param("AccessKeyId", myArgHttp.AccessKeyId.c_str());header.add_param("Action", myArgHttp.Action.c_str());header.add_param("Format", myArgHttp.Format.c_str());header.add_param("OutId", myArgHttp.OutId.c_str());header.add_param("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());header.add_param("RegionId", myArgHttp.RegionId.c_str());header.add_param("SignName", ASCII2UTF_8(myArgHttp.SignName).c_str());header.add_param("SignatureMethod", myArgHttp.SignatureMethod.c_str());header.add_param("SignatureNonce", bufNonce.c_str());header.add_param("SignatureVersion", myArgHttp.SignatureVersion.c_str());header.add_param("TemplateCode", myArgHttp.TemplateCode.c_str());header.add_param("TemplateParam", myArgHttp.TemplateParam.c_str());header.add_param("Timestamp", Timestamp.c_str());header.add_param("Version", myArgHttp.Version.c_str());bool rc = req.request(NULL, 0);//http请求// 将 build_request 放在 req.request 后面,是因为// req.request 内部可能会修改请求头中的字段acl::string hdr;header.build_request(hdr);printf("request header:\r\n%s\r\n", hdr.c_str());if (rc == false){printf( "send request error");return;}printf("send request ok!\r\n");// 取出 HTTP 响应头的 Content-Type 字段  const char* p = req.header_value("Content-Type");if (p == NULL || *p == 0){printf( "no Content-Type");return;}// 分析 HTTP 响应头的数据类型  acl::http_ctype content_type;content_type.parse(p);// 响应头数据类型的子类型  const char* stype = content_type.get_stype();bool ret;if (stype != NULL)ret = do_plain(req);if (ret == true)printf("read ok!");

三、编译测试效果

4)最终呈现效果

图二的签名与图一部一致是因为两张图片分别来自两个请求的截图

5)阿里云短信接口的http实现关键是做好签名,然后按通用的http访问请求实现即可,另外需要特别注意的是注意阿里里面短信定义要求,例如变量不能包含限制字符,变量长度不能超过20等等

C/C++开发,阿里云短信服务接口的c++实现相关推荐

  1. PHP开发阿里云短信服务接口

    PHP交流群:294088839 Python交流群:652376983 function sendSms($phone,$code){ // 基于TP3.2开发 //引进阿里的配置文件 Vendor ...

  2. 最新阿里云短信服务接口类【亲测成功】

    阿里大于 最新的阿里云短信接口,适用于阿里大于搬家以后的情况. 之前一直用阿里大于的短信接口,最近上项目时发现阿里大于悄悄地搬家到了阿里云!阿里云的SDK文件繁多,看得一头雾水!下面代码是最新的可适用 ...

  3. 阿里云短信服务接口返回: 只能向已回复授权信息的手机号发送

    项目场景: 在进入阿里云短信服务时,调用 OpenAPI-发送短信接口 , 返回异常情况及其解决. 问题描述 在进入阿里云短信服务时, 调用测试签名和测试短信模板后, 返回只能向已回复授权信息的手机号 ...

  4. 关于调用阿里云短信服务接口实现短信验证码的过程

    为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...

  5. 怎么样可以调用阿里云短信服务接口实现短信验证码

    为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...

  6. 调用阿里云短信服务接口实现短信验证码

    为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...

  7. 微信小程序云开发,使用阿里云短信服务,搜索员工生日定期发送短信。

    相关API文档地址: 阿里云短信服务API文档地址 小程序云开发云函数正则匹配API文档地址 小程序云开发云函数定时触发器 1.登录阿里云,购买短信服务并添加签名和模板 2., 登录阿里云,鼠标放在右 ...

  8. 阿里云短信服务详细说明与实战开发后端代码

    文章目录 1.短信服务背景 2.短信发送流程 3.阿里云短信服务基本说明 3.1 开通阿里云短信服务与购买短信套餐包 3.2 短信服务帮助文档 3.3 手机短信模板介绍 3.3.1 基本说明 3.3. ...

  9. 阿里云短信服务初次试用

    阿里云短信服务简单使用 提前声明,本人只是简单的试用了一下,终究还是止步于阿里复杂的业务逻辑(与开发无关,api还是很简单的),不仅又想起当年试用阿里的服务器时的场景,以及前几天阿里云出问题的新闻.. ...

最新文章

  1. luogu P3391 【模板】文艺平衡树(FHQ - treap,懒惰标记)
  2. 多边形填充算法-有序边表法(扫描线算法) 计算机图形学
  3. Android数据库存放的具体位置
  4. 随机抽样一致算法(RANSAC)理论介绍和程序实现
  5. RTT的线程同步篇——互斥量
  6. 9月16日见!vivo高管亲曝NEX 3 5G:99.6%屏占比确认
  7. 阿里云技术白皮书_2019年云计算发展白皮书发布 阿里云保持优势成亚太最大云服务商...
  8. 全面详解c语言使用cJSON解析JSON字符
  9. InoReader——网页无法打开
  10. 专用计算机的运行速度,WIN10专业版下电脑运行速度慢多个解决技巧
  11. PAT甲级-1118 Birds in Forest (25 分)
  12. Vijos 1523 贪吃的九头龙 【树形DP】
  13. CLH lock queue的原理解释及Java实现
  14. 2023年全国最新工会考试精选真题及答案37
  15. 不要再吐槽我R7000 2020的龙腾屏了,我给它换上了京东方的4K屏(已经填坑,谨慎踩坑)
  16. 笔的图片 html,笔的素描画图片
  17. 在 CloudIDE 里实现天猫精灵自定义技能的业务逻辑
  18. 对线性时不变系统(LTI)中时不变(Time Invariant)的一点点理解
  19. redis的使用(转载自:http://www.cnblogs.com/edisonfeng/p/3571870.html)
  20. win10ltsc安装后重启提示bitlocker有问题怎么办_TIA Portal博途常见的15大问题汇总

热门文章

  1. 【Android】录音机
  2. 对Cookie的理解
  3. python绘制3d动态模型_基于HTML5和WebGL的三维可视立体动态流程图
  4. 刷脸支付代理加盟要学会避坑,这些常规骗局你不得不防
  5. WPD-StackPanel中的控件水平居中
  6. 7000字长文|拆解淘金币运营策略,学习阿里怎么运营平台型积分体系运营
  7. 原创 | 如何从ArcGIS Online获取世界数据
  8. 一图看懂SAP仓储单位SU的应用
  9. 日语语言文学类毕业论文文献都有哪些?
  10. 西门子S7-1500PLC博途程序实例。 S7-1500博图程序水处理项目,具体为滤液生化段处理项目