Node Express微信公众号jssdk签名服务

开发公众号的过程中,会使用jssdk提供的微信公众号原生功能,使用过程中微信需要确认使用者身份,所以使用前需要现通过config接口注入权限验证配置,这时就需要用到签名服务,根据微信官方要求
Node Express微信公众号jssdk签名服务
对于不会开发后台服务的前端开发人员可以使用node来写服务端签名服务

相关依赖

package.json

有几个没用的依赖,用来调试别的功能的,可自行删除

{
  "name": "wechat-sign-service",
  "version": "1.0.0",
  "description": "",
  "main": "7001",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "saryz",
  "license": "ISC",
  "dependencies": {
    "baidu-aip-sdk": "^2.3.9",
    "body-parser": "^1.19.0",
    "cookie-parser": "~1.4.4",
    "crypto": "^1.0.1",
    "debug": "~2.6.9",
    "express": "^4.17.1",
    "fs": "0.0.1-security",
    "http": "0.0.0",
    "http-errors": "~1.6.3",
    "jade": "~1.11.0",
    "mime-types": "^2.1.24",
    "morgan": "~1.9.1",
    "multer": "^1.4.1",
    "path": "^0.12.7",
    "request": "^2.88.0",
    "sha1": "^1.1.1",
    "urlencode": "^1.1.0",
    "xunfeisdk": "^1.0.1"
  }
}

核心代码

service.js

// express
var express = require('express')
var request = require('request')
var sha1 = require('sha1')

var app = express()
var token = ''
var ticket = ''
var config = null

var appId = 'xxx'
var secret = 'xxx'
var url = ''

/**
 * token保持服务
 */
function keepAccessToken () {
  var getTokenUrl = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + appId + '&secret=' + secret
  request(reqOption(getTokenUrl), function (error, response, body) {
    if (!error && response.statusCode == 200) {
      token = body['access_token']
      console.log('刷新access_token=>>>', token.substr(0, 3) + '*****' + token.substr(-5)) // 请求成功的处理逻辑
      console.log('expires_in=>>>', body['expires_in']) // 请求成功的处理逻辑
      setTimeout(function () {
        keepAccessToken()
      }, body['expires_in']*1000)
    }
  })
}

/**
 * ticket保持服务
 */
function keepJsapiTicket () {
  if (token) {
    var getTicketUrl = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + token + '&type=jsapi'
    request(reqOption(getTicketUrl), function (error, response, body) {
      if (!error && response.statusCode == 200) {
        ticket = body['ticket']
        console.log('刷新ticket=>>', ticket.substr(0, 3) + '*****' + ticket.substr(-5)) // 请求成功的处理逻辑
        console.log('expires_in=>>>', body['expires_in']) // 请求成功的处理逻辑
        setTimeout(function () {
          keepJsapiTicket()
        }, body['expires_in']*1000)
      }
    })
  } else {
    setTimeout(function () {
      keepJsapiTicket()
    }, 1000)
  }

}

app.get('/wechatSdk/getConfig', function (req, res, next) {
  console.log('req=>>', req.param('url'))
  if (req.param('url') !== url) {
    url = req.param('url')
    config = null
  }
  getConfig(res)
})

function reqOption (url) {
  return {
    url: url,
    method: 'GET',
    json: true
  }
}

/**
 * 获取配置
 * @param res
 */
function getConfig (res) {
  var timestamp = Math.round(new Date().getTime() / 1000).toString()
  var nonceStr = randomString(16)

  console.log(url)
  var string = 'jsapi_ticket=' + ticket + '&noncestr=' + nonceStr + '&timestamp=' + timestamp + '&url=' + url
  var signature = sha1(string)

  config = {
    appId: appId, // 必填,公众号的唯一标识
    timestamp: timestamp, // 必填,生成签名的时间戳
    nonceStr: nonceStr, // 必填,生成签名的随机串
    signature: signature,// 必填,签名,见附录1
  }
  console.log('config===', config)
  res.send(config)
}

/**
 * 随机数
 * @param len
 * @returns {string}
 */
function randomString (len) {
  len = len || 32
  var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
  /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
  var maxPos = $chars.length
  var pwd = ''
  for (i = 0; i < len; i++) {
    pwd += $chars.charAt(Math.floor(Math.random() * maxPos))
  }
  return pwd
}
keepAccessToken()
keepJsapiTicket()
app.listen(3000)

启动

启动前请确保相关域名已加入微信公众号JS接口安全域名

正常启动

$node service.js

利用forever插件保持服务

// 全局安装forever
sudo npm install forever -g
// 启动服务 
forever start service.js
//查看当前服务目录
forever list
// 停止pid下的服务
forever stop [pid]
// 停止所有服务
forever stopall

使用

利用vuex做了持久化,也可以用别的方案替代

const url = location.href.replace(location.hash, '')
const wechatSign = this.$store.state.wechatSign
    if(wechatSign){
      wx.config({
        jsApiList: ['chooseImage'],
        openTagList: ['wx-open-launch-weapp'], // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
        ...wechatSign
      })
    }else{
      axios.get('/wechatSdk/getConfig',{params:{url}}).then(data => {
        console.log('config', data)
        this.$store.commit('setWechatSign', data)
        wx.config({
          jsApiList: ['chooseImage'],
          openTagList: ['wx-open-launch-weapp'], // 可选,需要使用的开放标签列表,例如['wx-open-launch-app']
          ...data
        })
      })
    }


上一篇:Vue集成飞书前端JSSDK


下一篇:js 使用微信公众号jssdk的接口,扫码,选择图片,获取位置信息