weixin.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. 'use strict';
  2. const assert = require('assert');
  3. const uuid = require('uuid');
  4. const _ = require('lodash');
  5. const { BusinessError, ErrorCode } = require('naf-core').Error;
  6. const crypto = require('crypto');
  7. const Service = require('egg').Service;
  8. class WeixinAuthService extends Service {
  9. constructor(ctx) {
  10. super(ctx, {});
  11. }
  12. // 取得微信AccessToken
  13. async accesstoken({ appid }) {
  14. assert(appid, '缺少appid参数项');
  15. const key = `visit:auth:accesstoken:${appid}`;
  16. const val = await this.app.redis.get(key);
  17. const data = {};
  18. if (val) {
  19. const { access_token } = JSON.parse(val);
  20. data.access_token = access_token;
  21. } else {
  22. const { wxapi } = this.app.config;
  23. const appidlist = wxapi;
  24. const wxapp = _.find(appidlist, { appid });
  25. const feturl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${wxapp.appSecret}`;
  26. const result = await this.ctx.curl(feturl, {
  27. method: 'get',
  28. headers: {
  29. 'content-type': 'application/json',
  30. },
  31. dataType: 'json',
  32. });
  33. console.log(result);
  34. if (result) {
  35. // console.log(result);
  36. const val = JSON.stringify(result.data);
  37. await this.app.redis.set(key, val, 'EX', 7200);
  38. data.access_token = result.data.access_token;
  39. }
  40. }
  41. console.log(`data=>${JSON.stringify(data)}`);
  42. return data;
  43. }
  44. // 取得微信jsapiticket
  45. async jsapiticket({ appid }) {
  46. assert(appid, '缺少appid参数项');
  47. const result = await this.accesstoken({ appid });
  48. const accesstoken = result.access_token;
  49. console.log(`accesstoken=>${accesstoken}`);
  50. assert(accesstoken, '缺少access_token参数项');
  51. const key = `visit:auth:jsapiticket:${appid}`;
  52. const val = await this.app.redis.get(key);
  53. const data = {};
  54. if (val) {
  55. const { ticket } = JSON.parse(val);
  56. data.ticket = ticket;
  57. } else {
  58. const feturl = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${accesstoken}&type=jsapi`;
  59. const result = await this.ctx.curl(feturl, {
  60. method: 'get',
  61. headers: {
  62. 'content-type': 'application/json',
  63. },
  64. dataType: 'json',
  65. });
  66. if (result) {
  67. // console.log(result);
  68. if (result.data.errcode === 0) {
  69. const val = JSON.stringify(result.data);
  70. await this.app.redis.set(key, val, 'EX', 7200);
  71. data.ticket = result.data.ticket;
  72. }
  73. }
  74. }
  75. return data;
  76. }
  77. // 签名算法
  78. async getsign({ appid, url }) {
  79. assert(appid, '缺少appid参数项');
  80. assert(url, '缺少url参数项');
  81. const result = await this.jsapiticket({ appid });
  82. // const { wxapi } = this.app.config;
  83. // const appidlist = wxapi;
  84. // const wxapp = _.find(appidlist, { appid });
  85. console.log(`url=>${url}`);
  86. const noncestr = await this.createNonceStr();
  87. const timestamp = await this.createTimestamp();
  88. const ret = {
  89. jsapi_ticket: result.ticket,
  90. noncestr,
  91. timestamp,
  92. url,
  93. };
  94. console.log(ret.data);
  95. const string = await this.raw(ret);
  96. ret.sign = await this.sha1(string);
  97. ret.appid = appid;
  98. // console.log('ret', ret);
  99. return ret;
  100. }
  101. // sha1加密
  102. async sha1(str) {
  103. const shasum = crypto.createHash('sha1');
  104. shasum.update(str);
  105. str = shasum.digest('hex');
  106. return str;
  107. }
  108. // 生成签名的时间戳
  109. async createTimestamp() {
  110. return parseInt(new Date().getTime() / 1000) + '';
  111. }
  112. // 生成签名的随机串
  113. async createNonceStr() {
  114. return Math.random().toString(36).substr(2, 15);
  115. }
  116. // 对参数对象进行字典排序
  117. // @param {对象} args 签名所需参数对象
  118. // @return {字符串} 排序后生成字符串
  119. async raw(args) {
  120. let keys = Object.keys(args);
  121. keys = keys.sort();
  122. const newArgs = {};
  123. keys.forEach(function(key) {
  124. newArgs[key.toLowerCase()] = args[key];
  125. });
  126. let string = '';
  127. for (const k in newArgs) {
  128. string += '&' + k + '=' + newArgs[k];
  129. }
  130. string = string.substr(1);
  131. return string;
  132. }
  133. }
  134. module.exports = WeixinAuthService;