weixin.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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. if (result) {
  34. // console.log(result);
  35. const val = JSON.stringify(result.data);
  36. await this.app.redis.set(key, val, 'EX', 7200);
  37. data.access_token = result.data.access_token;
  38. }
  39. }
  40. return data;
  41. }
  42. // 取得微信jsapiticket
  43. async jsapiticket({ appid }) {
  44. assert(appid, '缺少appid参数项');
  45. const result = await this.accesstoken({ appid });
  46. const accesstoken = result.access_token;
  47. assert(accesstoken, '缺少access_token参数项');
  48. const key = `visit:auth:jsapiticket:${appid}`;
  49. const val = await this.app.redis.get(key);
  50. const data = {};
  51. if (val) {
  52. const { ticket } = JSON.parse(val);
  53. data.ticket = ticket;
  54. } else {
  55. const feturl = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${accesstoken}&type=jsapi`;
  56. const result = await this.ctx.curl(feturl, {
  57. method: 'get',
  58. headers: {
  59. 'content-type': 'application/json',
  60. },
  61. dataType: 'json',
  62. });
  63. if (result) {
  64. if (result.data.errcode === 0) {
  65. const val = JSON.stringify(result.data);
  66. await this.app.redis.set(key, val, 'EX', 7200);
  67. data.ticket = result.data.ticket;
  68. }
  69. }
  70. }
  71. return data;
  72. }
  73. // 签名算法
  74. async getsign({ appid, url }) {
  75. assert(appid, '缺少appid参数项');
  76. assert(url, '缺少url参数项');
  77. const result = await this.jsapiticket({ appid });
  78. // const { wxapi } = this.app.config;
  79. // const appidlist = wxapi;
  80. // const wxapp = _.find(appidlist, { appid });
  81. const noncestr = await this.createNonceStr();
  82. const timestamp = await this.createTimestamp();
  83. const ret = {
  84. jsapi_ticket: result.ticket,
  85. noncestr,
  86. timestamp,
  87. url,
  88. };
  89. const string = await this.raw(ret);
  90. ret.sign = await this.sha1(string);
  91. ret.appid = appid;
  92. return ret;
  93. }
  94. // sha1加密
  95. async sha1(str) {
  96. const shasum = crypto.createHash('sha1');
  97. shasum.update(str);
  98. str = shasum.digest('hex');
  99. return str;
  100. }
  101. // 生成签名的时间戳
  102. async createTimestamp() {
  103. return parseInt(new Date().getTime() / 1000) + '';
  104. }
  105. // 生成签名的随机串
  106. async createNonceStr() {
  107. return Math.random().toString(36).substr(2, 15);
  108. }
  109. // 对参数对象进行字典排序
  110. // @param {对象} args 签名所需参数对象
  111. // @return {字符串} 排序后生成字符串
  112. async raw(args) {
  113. let keys = Object.keys(args);
  114. keys = keys.sort();
  115. const newArgs = {};
  116. keys.forEach(function(key) {
  117. newArgs[key.toLowerCase()] = args[key];
  118. });
  119. let string = '';
  120. for (const k in newArgs) {
  121. string += '&' + k + '=' + newArgs[k];
  122. }
  123. string = string.substr(1);
  124. return string;
  125. }
  126. }
  127. module.exports = WeixinAuthService;