/** * 1. appId 必填,公众号的唯一标识 * 2. timestamp 必填,生成签名的时间戳 * 3. nonceStr 必填,生成签名的随机串 * 4. signature 必填,签名 */ const crypto = require('crypto') const getJsTicket = require('./getJsTicket') const config = require('../../config') // 微信设置 // sha1加密 function sha1(str) { let shasum = crypto.createHash("sha1") shasum.update(str) str = shasum.digest("hex") return str } /** * 生成签名的时间戳 * @return {字符串} */ function createTimestamp () { return parseInt(new Date().getTime() / 1000) + '' } /** * 生成签名的随机串 * @return {字符串} */ function createNonceStr () { return Math.random().toString(36).substr(2, 15) } /** * 对参数对象进行字典排序 * @param {对象} args 签名所需参数对象 * @return {字符串} 排序后生成字符串 */ function raw (args) { var keys = Object.keys(args) keys = keys.sort() var newArgs = {} keys.forEach(function (key) { newArgs[key.toLowerCase()] = args[key] }) var string = '' for (var k in newArgs) { string += '&' + k + '=' + newArgs[k] } string = string.substr(1) return string } /** * @synopsis 签名算法 * * @param jsapi_ticket 用于签名的 jsapi_ticket * @param url 用于签名的 url ,注意必须动态获取,不能 hardcode * * @returns {对象} 返回微信jssdk所需参数对象 */ function sign (jsapi_ticket, url) { var ret = { jsapi_ticket: jsapi_ticket, nonceStr: createNonceStr(), timestamp: createTimestamp(), url: url } var string = raw(ret) ret.signature = sha1(string) ret.appId = config.appid return ret } /** * 返回微信jssdk 所需参数对象 * @param {字符串} url 当前访问URL * @return {promise} 返回promise类 val为对象 */ function jsSdk (url) { return getJsTicket() .then(function (ticket) { return sign(ticket, url) }) .catch(function (err) { console.log(err) }) } function routerSdk (req, res, next) { let clientUrl = req.body.url if (clientUrl) { jsSdk(clientUrl) .then(function (obj) { res.json(obj) }) } else { res.end('no url') } } module.exports = routerSdk
以上基本就完成了后端返回签名的过程(省略了redis部分)。具体细节可参考我当时的练手项目中的代码。
至此,前端就可以使用jssdk来完成功能的调用了。
ps:某次使用录音接口做了一个功能,但是发现,微信服务器只会保存3天数据,需要自己下载到自己的服务器才行,不知道诸位有没做过类似的需求,给我提供下指导啥的,感激不尽~
后记
后来又写过一个获取用户信息的页面,感觉也是挺常用的就写个demo出来看看吧(没有做access_token的保存,好像是没有获取次数限制)。
router.get('https://www.jb51.net/', function(req, res, next){ console.log("oauth - login") // 第一步:用户同意授权,获取code let router = 'get_wx_access_token' // 这是编码后的地址 let return_uri = encodeURIComponent(base_url + router) console.log('回调地址:' + return_uri) let scope = 'snsapi_userinfo' res.redirect('https://open.weixin.qq.com/connect/oauth2/authorize?appid='+appid+'&redirect_uri='+return_uri+'&response_type=code&scope='+scope+'&state=STATE#wechat_redirect') }) // 第二步:通过code换取网页授权access_token router.get('/get_wx_access_token', function(req,res, next){ console.log("get_wx_access_token") console.log("code_return: "+req.query.code) let code = req.query.code request.get( { url:'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' + appid + '&secret=' + appsecret+'&code=' + code + '&grant_type=authorization_code', }, function(error, response, body){ if(response.statusCode === 200){ // 第三步:拉取用户信息(需scope为 snsapi_userinfo) // console.log(JSON.parse(body)) let data = JSON.parse(body) let access_token = data.access_token let openid = data.openid request.get( { url:'https://api.weixin.qq.com/sns/userinfo?access_token='+access_token+'&openid='+openid+'&lang=zh_CN', }, function(error, response, body){ if(response.statusCode == 200){ // 第四步:根据获取的用户信息进行对应操作 let userinfo = JSON.parse(body) console.log(JSON.parse(body)) console.log('获取微信信息成功!') 小测试,实际应用中,可以由此创建一个帐户 res.send("\ <h1>"+userinfo.nickname+" 的个人信息</h1>\ <p><img src='"https://www.jb51.net/+userinfo.headimgurl+"' /></p>\ <p>"+userinfo.city+","+userinfo.province+","+userinfo.country+"</p>\ ") }else{ console.log(response.statusCode) } } ) }else{ console.log(response.statusCode) } } ) })