C/C++开发,阿里云短信服务接口的c++实现
目录
一、阿里云短信服务接口
二、逻辑代码实现
三、编译测试效果
一、阿里云短信服务接口
最近在调用阿里云短信服务接口发现并没有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++实现相关推荐
- PHP开发阿里云短信服务接口
PHP交流群:294088839 Python交流群:652376983 function sendSms($phone,$code){ // 基于TP3.2开发 //引进阿里的配置文件 Vendor ...
- 最新阿里云短信服务接口类【亲测成功】
阿里大于 最新的阿里云短信接口,适用于阿里大于搬家以后的情况. 之前一直用阿里大于的短信接口,最近上项目时发现阿里大于悄悄地搬家到了阿里云!阿里云的SDK文件繁多,看得一头雾水!下面代码是最新的可适用 ...
- 阿里云短信服务接口返回: 只能向已回复授权信息的手机号发送
项目场景: 在进入阿里云短信服务时,调用 OpenAPI-发送短信接口 , 返回异常情况及其解决. 问题描述 在进入阿里云短信服务时, 调用测试签名和测试短信模板后, 返回只能向已回复授权信息的手机号 ...
- 关于调用阿里云短信服务接口实现短信验证码的过程
为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...
- 怎么样可以调用阿里云短信服务接口实现短信验证码
为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...
- 调用阿里云短信服务接口实现短信验证码
为了实现给手机发送短信来进行验证码验证,所以需要调用此接口来进行测试 登陆阿里云 首先需要有阿里云的账号,进行注册申请,进去控制台,然后找到短信服务 创建签名和模板 选中国内消息,然后看到右边有签名管 ...
- 微信小程序云开发,使用阿里云短信服务,搜索员工生日定期发送短信。
相关API文档地址: 阿里云短信服务API文档地址 小程序云开发云函数正则匹配API文档地址 小程序云开发云函数定时触发器 1.登录阿里云,购买短信服务并添加签名和模板 2., 登录阿里云,鼠标放在右 ...
- 阿里云短信服务详细说明与实战开发后端代码
文章目录 1.短信服务背景 2.短信发送流程 3.阿里云短信服务基本说明 3.1 开通阿里云短信服务与购买短信套餐包 3.2 短信服务帮助文档 3.3 手机短信模板介绍 3.3.1 基本说明 3.3. ...
- 阿里云短信服务初次试用
阿里云短信服务简单使用 提前声明,本人只是简单的试用了一下,终究还是止步于阿里复杂的业务逻辑(与开发无关,api还是很简单的),不仅又想起当年试用阿里的服务器时的场景,以及前几天阿里云出问题的新闻.. ...
最新文章
- luogu P3391 【模板】文艺平衡树(FHQ - treap,懒惰标记)
- 多边形填充算法-有序边表法(扫描线算法) 计算机图形学
- Android数据库存放的具体位置
- 随机抽样一致算法(RANSAC)理论介绍和程序实现
- RTT的线程同步篇——互斥量
- 9月16日见!vivo高管亲曝NEX 3 5G:99.6%屏占比确认
- 阿里云技术白皮书_2019年云计算发展白皮书发布 阿里云保持优势成亚太最大云服务商...
- 全面详解c语言使用cJSON解析JSON字符
- InoReader——网页无法打开
- 专用计算机的运行速度,WIN10专业版下电脑运行速度慢多个解决技巧
- PAT甲级-1118 Birds in Forest (25 分)
- Vijos 1523 贪吃的九头龙 【树形DP】
- CLH lock queue的原理解释及Java实现
- 2023年全国最新工会考试精选真题及答案37
- 不要再吐槽我R7000 2020的龙腾屏了,我给它换上了京东方的4K屏(已经填坑,谨慎踩坑)
- 笔的图片 html,笔的素描画图片
- 在 CloudIDE 里实现天猫精灵自定义技能的业务逻辑
- 对线性时不变系统(LTI)中时不变(Time Invariant)的一点点理解
- redis的使用(转载自:http://www.cnblogs.com/edisonfeng/p/3571870.html)
- win10ltsc安装后重启提示bitlocker有问题怎么办_TIA Portal博途常见的15大问题汇总