PayApi.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. #include "StdAfx.h"
  2. #include "PayApi.h"
  3. #include <algorithm>
  4. #include "EncodingConversion.h"
  5. // 支付宝公共参数;
  6. const string Alipay_default_charset = "utf-8";
  7. const string Alipay_default_url = "https://openapi.alipay.com/gateway.do";
  8. const string Alipay_default_sign_type = "RSA";
  9. const string Alipay_default_version = "1.0";
  10. const string Alipay_appid = "app_id";
  11. const string Alipay_method = "method";
  12. const string Alipay_charset = "charset";
  13. const string Alipay_signtype = "sign_type";
  14. const string Alipay_sign = "sign";
  15. const string Alipay_timestamp = "timestamp";
  16. const string Alipay_version = "version";
  17. const string Alipay_bizcontenr = "biz_content";
  18. PayApi::PayApi(void)
  19. {
  20. }
  21. PayApi::~PayApi(void)
  22. {
  23. }
  24. /************************************************************************/
  25. /* 函数:base64Encode[3/30/2017 Jeff];
  26. /* 描述:将字符串转成base64格式;
  27. /* 参数:;
  28. /* [IN] bytes:要转的字符串指针;
  29. /* [IN] len:字符串长度;
  30. /* 返回:void;
  31. /* 注意:;
  32. /* 示例:;
  33. /*
  34. /* 修改:;
  35. /* 日期:;
  36. /* 内容:;
  37. /************************************************************************/
  38. string PayApi::base64Encode(const unsigned char *bytes, int len)
  39. {
  40. BIO *bmem = NULL;
  41. BIO *b64 = NULL;
  42. BUF_MEM *bptr = NULL;
  43. b64 = BIO_new(BIO_f_base64());
  44. BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  45. bmem = BIO_new(BIO_s_mem());
  46. b64 = BIO_push(b64, bmem);
  47. BIO_write(b64, bytes, len);
  48. BIO_flush(b64);
  49. BIO_get_mem_ptr(b64, &bptr);
  50. string str = string(bptr->data, bptr->length);
  51. BIO_free_all(b64);
  52. return str;
  53. }
  54. /************************************************************************/
  55. /* 函数:base64Decode[3/30/2017 Jeff];
  56. /* 描述:解码base64字符串;
  57. /* 参数:;
  58. /* [IN] str:要解码的base64字符串;
  59. /* [OUT] bytes:存储解码结果的字符串缓存指针;
  60. /* [OUT] len:解码后的字符串长度;
  61. /* 返回:void;
  62. /* 注意:;
  63. /* 示例:;
  64. /*
  65. /* 修改:;
  66. /* 日期:;
  67. /* 内容:;
  68. /************************************************************************/
  69. bool PayApi::base64Decode(const string &str, unsigned char *bytes, int &len)
  70. {
  71. const char *cstr = str.c_str();
  72. BIO *bmem = NULL;
  73. BIO *b64 = NULL;
  74. b64 = BIO_new(BIO_f_base64());
  75. BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  76. bmem = BIO_new_mem_buf((void *)cstr, strlen(cstr));
  77. b64 = BIO_push(b64, bmem);
  78. len = BIO_read(b64, bytes, len);
  79. BIO_free_all(b64);
  80. return len > 0;
  81. }
  82. /************************************************************************/
  83. /* 函数:rsaSign[3/30/2017 Jeff];
  84. /* 描述:rsa签名;
  85. /* 参数:;
  86. /* [IN] content:要使用rsa签名的字符串;
  87. /* [IN] key:rsa签名的密钥;
  88. /* 返回:void;
  89. /* 注意:;
  90. /* 示例:;
  91. /*
  92. /* 修改:;
  93. /* 日期:;
  94. /* 内容:;
  95. /************************************************************************/
  96. string PayApi::rsaSign(const string &content, const string &key)
  97. {
  98. string signed_str;
  99. const char *key_cstr = key.c_str();
  100. int key_len = strlen(key_cstr);
  101. BIO *p_key_bio = BIO_new_mem_buf((void *)key_cstr, key_len);
  102. RSA *p_rsa = PEM_read_bio_RSAPrivateKey(p_key_bio, NULL, NULL, NULL);
  103. if (p_rsa != NULL) {
  104. const char *cstr = content.c_str();
  105. unsigned char hash[SHA_DIGEST_LENGTH] = { 0 };
  106. SHA1((unsigned char *)cstr, strlen(cstr), hash);
  107. unsigned char sign[XRSA_KEY_BITS / 8] = { 0 };
  108. unsigned int sign_len = sizeof(sign);
  109. int r = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sign, &sign_len, p_rsa);
  110. if (0 != r && sizeof(sign) == sign_len) {
  111. signed_str = base64Encode(sign, sign_len);
  112. }
  113. }
  114. RSA_free(p_rsa);
  115. BIO_free(p_key_bio);
  116. return signed_str;
  117. }
  118. /************************************************************************/
  119. /* 函数:rsaVerify[3/30/2017 Jeff];
  120. /* 描述:rsa签名验证;
  121. /* 参数:;
  122. /* [IN] content:要验证的字符串;
  123. /* [IN] sign:验证比较的rsa签名;
  124. /* [IN] key:rsa签名的密钥;
  125. /* 返回:void;
  126. /* 注意:;
  127. /* 示例:;
  128. /*
  129. /* 修改:;
  130. /* 日期:;
  131. /* 内容:;
  132. /************************************************************************/
  133. bool PayApi::rsaVerify(const string &content, const string &sign, const string &key)
  134. {
  135. bool result = false;
  136. const char *key_cstr = key.c_str();
  137. int key_len = strlen(key_cstr);
  138. BIO *p_key_bio = BIO_new_mem_buf((void *)key_cstr, key_len);
  139. RSA *p_rsa = PEM_read_bio_RSA_PUBKEY(p_key_bio, NULL, NULL, NULL);
  140. if (p_rsa != NULL) {
  141. const char *cstr = content.c_str();
  142. unsigned char hash[SHA_DIGEST_LENGTH] = { 0 };
  143. SHA1((unsigned char *)cstr, strlen(cstr), hash);
  144. unsigned char sign_cstr[XRSA_KEY_BITS / 8] = { 0 };
  145. int len = XRSA_KEY_BITS / 8;
  146. base64Decode(sign, sign_cstr, len);
  147. unsigned int sign_len = XRSA_KEY_BITS / 8;
  148. int r = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, (unsigned char *)sign_cstr, sign_len, p_rsa);
  149. if (r > 0) {
  150. result = true;
  151. }
  152. }
  153. RSA_free(p_rsa);
  154. BIO_free(p_key_bio);
  155. return result;
  156. }
  157. /************************************************************************/
  158. /* 函数:alipay_setCommonParam[3/30/2017 Jeff];
  159. /* 描述:设置支付宝支付的公共参数;
  160. /* 参数:;
  161. /* [IN] appid:支付宝分配开发者的应用ID;
  162. /* [IN] privatekey:私钥;
  163. /* [IN] signtype:签名方式;
  164. /* [IN] charset:字符集;
  165. /* [IN] version:版本;
  166. /* [IN] url:主url;
  167. /* [IN] publickey:公钥;
  168. /* 返回:void;
  169. /* 注意:;
  170. /* 示例:;
  171. /*
  172. /* 修改:;
  173. /* 日期:;
  174. /* 内容:;
  175. /************************************************************************/
  176. void PayApi::alipay_setCommonParam( const string &appid, const string &privatekey, const string &signtype, const string &charset, const string &version, const string &url, const string &publickey )
  177. {
  178. alipay_appid = appid;
  179. alipay_privatekey = privatekey;
  180. alipay_signtype = signtype;
  181. alipay_charset = charset;
  182. alipay_version = version;
  183. alipay_url = url;
  184. alipay_PublicKey = publickey;
  185. }
  186. /************************************************************************/
  187. /* 函数:[3/30/2017 Jeff];
  188. /* 描述:;
  189. /* 参数:;
  190. /* [IN] :;
  191. /* [OUT] :;
  192. /* [IN/OUT] :;
  193. /* 返回:void;
  194. /* 注意:;
  195. /* 示例:;
  196. /*
  197. /* 修改:;
  198. /* 日期:;
  199. /* 内容:;
  200. /************************************************************************/
  201. string PayApi::buildContent(const StringMap &contentPairs)
  202. {
  203. string content;
  204. for (StringMap::const_iterator iter = contentPairs.begin();
  205. iter != contentPairs.end(); ++iter) {
  206. if (!content.empty()) {
  207. content.push_back('&');
  208. }
  209. content.append(iter->first);
  210. content.push_back('=');
  211. content.append(iter->second);
  212. }
  213. return content;
  214. }
  215. /************************************************************************/
  216. /* 函数:[3/30/2017 Jeff];
  217. /* 描述:;
  218. /* 参数:;
  219. /* [IN] :;
  220. /* [OUT] :;
  221. /* [IN/OUT] :;
  222. /* 返回:void;
  223. /* 注意:;
  224. /* 示例:;
  225. /*
  226. /* 修改:;
  227. /* 日期:;
  228. /* 内容:;
  229. /************************************************************************/
  230. string PayApi::alipay_invoke(const string & method, const JsonMap & contentMap, const StringMap & extendParamMap)
  231. {
  232. string content = JsonUtil::objectToString(JsonType(contentMap));
  233. return alipay_invoke(method, content, extendParamMap);
  234. }
  235. /************************************************************************/
  236. /* 函数:[3/30/2017 Jeff];
  237. /* 描述:;
  238. /* 参数:;
  239. /* [IN] :;
  240. /* [OUT] :;
  241. /* [IN/OUT] :;
  242. /* 返回:void;
  243. /* 注意:;
  244. /* 示例:;
  245. /*
  246. /* 修改:;
  247. /* 日期:;
  248. /* 内容:;
  249. /************************************************************************/
  250. JsonMap PayApi::alipay_Str2JsonMap(string strJson)
  251. {
  252. //获取返回报文中的alipay_xxx_xxx_response的内容;
  253. int beg = strJson.find("_response\"");
  254. int end = strJson.rfind("\"sign\"");
  255. if (beg < 0 || end < 0)
  256. {
  257. JsonType jsonObj = JsonUtil::stringToObject(strJson);
  258. return jsonObj.toMap();
  259. }
  260. beg = strJson.find('{', beg);
  261. end = strJson.rfind('}', end);
  262. strJson = strJson.substr(beg, end - beg + 1);
  263. JsonType jsonObj = JsonUtil::stringToObject(strJson);
  264. return jsonObj.toMap();
  265. }
  266. /************************************************************************/
  267. /* 函数:[3/31/2017 Jeff];
  268. /* 描述:;
  269. /* 参数:;
  270. /* [IN] :;
  271. /* [OUT] :;
  272. /* [IN/OUT] :;
  273. /* 返回:void;
  274. /* 注意:;
  275. /* 示例:;
  276. /*
  277. /* 修改:;
  278. /* 日期:;
  279. /* 内容:;
  280. /************************************************************************/
  281. string PayApi::alipay_invoke(const string & method, const string & content, const StringMap & extendParamMap)
  282. {
  283. // 生成时间缀;
  284. time_t t = time(0);
  285. char tmp[64];
  286. strftime(tmp, sizeof(tmp), "%Y-%m-%d %X", localtime(&t));
  287. // 补全公共参数;
  288. StringMap requestPairs;
  289. requestPairs.insert(StringMap::value_type(Alipay_appid, alipay_appid));
  290. requestPairs.insert(StringMap::value_type(Alipay_bizcontenr, content));
  291. requestPairs.insert(StringMap::value_type(Alipay_charset, alipay_charset));
  292. requestPairs.insert(StringMap::value_type(Alipay_method, method));
  293. requestPairs.insert(StringMap::value_type(Alipay_signtype, alipay_signtype));
  294. requestPairs.insert(StringMap::value_type(Alipay_timestamp, tmp));
  295. requestPairs.insert(StringMap::value_type(Alipay_version, alipay_version));
  296. /** 追加外部传入的网关的补充参数,如notify_url等 **/
  297. for (StringMap::const_iterator iter = extendParamMap.begin(); iter != extendParamMap.end(); ++iter) {
  298. requestPairs.insert(StringMap::value_type(iter->first, iter->second));
  299. }
  300. string wholeContent = buildContent(requestPairs);
  301. string sign = rsaSign(wholeContent, alipay_privatekey);
  302. requestPairs.insert(StringMap::value_type(Alipay_sign, sign));
  303. wholeContent = buildContent(requestPairs);
  304. #ifdef _DEBUG
  305. WriteTextLog("\r\nRequest:%s\r\n", wholeContent.c_str());
  306. #endif
  307. HttpClient httpClient;
  308. string responseStr = httpClient.sendSyncRequest(alipay_url, requestPairs);
  309. #ifdef _DEBUG
  310. WriteTextLog("\r\nResponse:%s\r\n", responseStr.c_str());
  311. #endif
  312. // 验签失败原因未找到,暂时不处理;
  313. //string responseContent = analyzeAliResponse(responseStr);
  314. //return responseContent;
  315. return responseStr;
  316. }
  317. string PayApi::analyzeAliResponse(const string & responseStr)
  318. {
  319. JsonType responseObj = JsonUtil::stringToObject(responseStr);
  320. JsonMap responseMap = responseObj.toMap();
  321. //获取返回报文中的alipay_xxx_xxx_response的内容;
  322. int beg = responseStr.find("_response\"");
  323. int end = responseStr.rfind("\"sign\"");
  324. if (beg < 0 || end < 0)
  325. {
  326. return string();
  327. }
  328. beg = responseStr.find('{', beg);
  329. end = responseStr.rfind('}', end);
  330. //注意此处将map转为json之后的结果需要与支付宝返回报文中原格式与排序一致;
  331. //排序规则是节点中的各个json节点key首字母做字典排序;
  332. //Response的Json值内容需要包含首尾的“{”和“}”两个尖括号,双引号也需要参与验签;
  333. //如果字符串中包含“http://”的正斜杠,需要先将正斜杠做转义,默认打印出来的字符串是已经做过转义的;
  334. //此处转换之后的json字符串默认为"Compact"模式,即紧凑模式,不要有空格与换行;
  335. string responseContent = responseStr.substr(beg, end - beg + 1);
  336. DebugLog("ResponseContent:%s", responseContent.c_str());
  337. //此处为校验支付宝返回报文中的签名;
  338. //如果支付宝公钥为空,则默认跳过该步骤,不校验签名;
  339. //如果支付宝公钥不为空,则认为需要校验签名;
  340. if (!alipay_PublicKey.empty())
  341. {
  342. DebugLog("AlipayPublicKey:%s", alipay_PublicKey.c_str());
  343. JsonMap::const_iterator iter = responseMap.find(Alipay_sign);
  344. if (iter == responseMap.end())
  345. {
  346. DebugLog("Cannot get Sign from response, Verify Failed");
  347. return string();
  348. }
  349. //获取返回报文中的sign;
  350. string responseSign = iter->second.toString();
  351. DebugLog("ResponseSign:%s", responseSign.c_str());
  352. //调用验签方法;
  353. bool verifyResult = rsaVerify(responseContent, responseSign, alipay_PublicKey);
  354. if (!verifyResult) {
  355. DebugLog("Verify Failed");
  356. return string();
  357. }
  358. DebugLog("Verify Success");
  359. }
  360. else
  361. {
  362. DebugLog("AlipayPublicKey is empty, Skip the Verify");
  363. }
  364. return responseContent;
  365. }
  366. /************************************************************************/
  367. /* 函数:[3/31/2017 Jeff];
  368. /* 描述:;
  369. /* 参数:;
  370. /* [IN] :;
  371. /* [OUT] :;
  372. /* [IN/OUT] :;
  373. /* 返回:void;
  374. /* 注意:;
  375. /* 示例:;
  376. /*
  377. /* 修改:;
  378. /* 日期:;
  379. /* 内容:;
  380. /************************************************************************/
  381. void PayApi::wxpay_setCommonParam(const string & appid, const string & mchid, const string & privatekey)
  382. {
  383. wxpay_appid = appid;
  384. wxpay_mchid = mchid;
  385. wxpay_privatekey = privatekey;
  386. }
  387. /************************************************************************/
  388. /* 函数:[3/30/2017 Jeff];
  389. /* 描述:;
  390. /* 参数:;
  391. /* [IN] :;
  392. /* [OUT] :;
  393. /* [IN/OUT] :;
  394. /* 返回:void;
  395. /* 注意:;
  396. /* 示例:;
  397. /*
  398. /* 修改:;
  399. /* 日期:;
  400. /* 内容:;
  401. /************************************************************************/
  402. string PayApi::wxapi_getSign(StringMap &strMap, string key)
  403. {
  404. string strtemp;
  405. vector<string> vtString;
  406. for (StringMap::const_iterator iter = strMap.begin(); iter != strMap.end(); iter++)
  407. {
  408. if ( _tcscmp(iter->first.c_str(), "sign") != 0 && iter->second.size() != 0 )
  409. {// 除去sign本身;
  410. strtemp = iter->first;
  411. strtemp.append("=");
  412. strtemp.append(iter->second);
  413. vtString.push_back(strtemp);
  414. }
  415. }
  416. strtemp.clear();
  417. std::sort(vtString.begin(), vtString.end());
  418. for (vector<string>::iterator it = vtString.begin(); it != vtString.end(); it++ )
  419. {
  420. strtemp.append(it->c_str());
  421. strtemp.append("&");
  422. }
  423. strtemp.append("key=");
  424. strtemp.append(key);
  425. #ifdef _DEBUG
  426. WriteTextLog("合并:%s\n", strtemp.c_str());
  427. #endif
  428. // 计算MD5,必须使用utf-8来计算;
  429. EncodingConverion::ASCII2UTF8(strtemp.c_str(), strtemp);
  430. // md5加密;
  431. MD5_CTX ctx;
  432. char sztmp[3] = {0};
  433. unsigned char szmd[16] = {0};
  434. MD5_Init(&ctx);
  435. MD5_Update(&ctx, strtemp.data(), strtemp.size());
  436. MD5_Final(szmd, &ctx);
  437. strtemp.clear();
  438. for ( int i = 0; i < 16; i++ )
  439. {
  440. sprintf_s(sztmp, "%02X", szmd[i]);
  441. strtemp.append(sztmp);
  442. }
  443. #ifdef _DEBUG
  444. WriteTextLog("MD5:%s\n", strtemp.c_str());
  445. #endif
  446. return strtemp;
  447. }
  448. /************************************************************************/
  449. /* 函数:[3/30/2017 Jeff];
  450. /* 描述:;
  451. /* 参数:;
  452. /* [IN] :;
  453. /* [OUT] :;
  454. /* [IN/OUT] :;
  455. /* 返回:void;
  456. /* 注意:;
  457. /* 示例:;
  458. /*
  459. /* 修改:;
  460. /* 日期:;
  461. /* 内容:;
  462. /************************************************************************/
  463. string PayApi::wxpay_invoke(const string &method, StringMap &extendParamMap, string key )
  464. {
  465. // 计算出签名;
  466. string sign = wxapi_getSign(extendParamMap, key);
  467. // 将签名加入;
  468. extendParamMap.insert(StringMap::value_type("sign", sign));
  469. tinyxml2::XMLDocument doc;
  470. tinyxml2::XMLNode *node = doc.InsertEndChild(doc.NewElement("xml"));
  471. tinyxml2::XMLElement *subelement = NULL;
  472. for (StringMap::const_iterator iter = extendParamMap.begin(); iter != extendParamMap.end(); ++iter)
  473. {
  474. subelement = doc.NewElement(iter->first.c_str());
  475. subelement->SetText(iter->second.c_str());
  476. node->InsertEndChild(subelement);
  477. }
  478. tinyxml2::XMLPrinter printer;
  479. doc.Print(&printer);
  480. string result = printer.CStr();
  481. EncodingConverion::ASCII2UTF8(result.c_str(), result);
  482. HttpClient httpClient;
  483. string responseStr = httpClient.sendSyncRequest(method, result);
  484. EncodingConverion::UTF82ASCII(responseStr.c_str(), responseStr);
  485. #ifdef _DEBUG
  486. WriteTextLog("返回码:%s\n", responseStr.c_str());
  487. #endif
  488. DebugLog("Response:%s", responseStr.c_str());
  489. return responseStr;
  490. }
  491. /************************************************************************/
  492. /* 函数:[3/30/2017 Jeff];
  493. /* 描述:;
  494. /* 参数:;
  495. /* [IN] :;
  496. /* [OUT] :;
  497. /* [IN/OUT] :;
  498. /* 返回:void;
  499. /* 注意:;
  500. /* 示例:;
  501. /*
  502. /* 修改:;
  503. /* 日期:;
  504. /* 内容:;
  505. /************************************************************************/
  506. string PayApi::analyzeWXRespone(const string &respone)
  507. {
  508. return "";
  509. }