JS-SDK鉴权流程

简介
全栈实现JS-SDK鉴权流程,前端使用vue的技术栈,后端使用Express和mongodb,实现access_token的缓存与更新。
整体流程

公众号配置
服务器配置

IP白名单

JS接口安全域名

❝
注意事项: 这里配置的域名等需要公网可访问,可以使用内网穿透工具,请看相关工具
❞
前端
❝
核心代码
❞
<html>
<head>
<title>微信JS-SDK调用Demo</title>
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="/stylesheets/base.css">
<script src="https://res.wx.qq.com/open/js/jweixin-1.3.2.js"></script>
<script src="https://cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>
<script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
</head>
<body>
<div id="app">
<h1>微信JS-SDK调用Demo {{ wxReady }}</h1>
<p @click="scanCode(0)">扫描二维码--微信处理</p>
<p @click="scanCode(1)">扫描二维码--自行处理</p>
<div v-if="scanResult">scanResult: {{ scanResult }}</div>
</div>
</body>
<script>
var vConsole = new window.VConsole();
new Vue({
el: '#app',
data: () => {
return {
result: {},
scanResult: '',
wxReady: ''
}
},
mounted() {
this.wxconfig();
},
methods: {
wxconfig() {
console.log('获取 wxconfig', window.wx);
// let url = encodeURIComponent(location.href.split('#')[0])
// 改地址为使用花生壳将本地服务做的映射
const _this = this
let url = 'https://2z42z99186.imdo.co/'
axios.get(`https://2z42z99186.imdo.co/jsapi?url=${url}`).then((result) => {
console.log('jsapi接口数据', result.data);
this.result = result.data
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
...result.data,
jsApiList: [
'scanQRCode'
] // 必填,需要使用的JS接口列表
});
wx.ready(function () {
_this.wxReady = 'wx.ready'
});
wx.error(function (a, b) {
_this.wxReady = 'wx.error'
});
}).catch(err => {
console.log('err', err);
})
},
scanCode(type) {
const that = this
wx.scanQRCode({
needResult: type, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
// 当needResult 为 1 时,扫码返回的结果
that.scanResult = res.resultStr
}
});
}
},
})
</script>
</html>
后端
❝
核心代码
❞
鉴权接口
router.get('/jsapi', async function (req, res) {
let url = decodeURIComponent(req.query.url);
let conf = await sign(url);
res.send(conf);
})
处理签名
require('dotenv').config();
const axios = require('axios')
const ticketModel = require('../db/models/ticketModel')
const crypto = require('crypto');
appid = process.env.APPID
secret = process.env.SECRET
// 生成随机字符串
function createNonceStr() {
return Math.random().toString(36).substr(2, 15);
}
// 生成时间戳
function createTimestamp() {
return parseInt(new Date().getTime() / 1000) + '';
}
// 获取 access_token
async function getAccessToken() {
let tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`
let tokenTata = await axios.get(tokenUrl);
console.log('tokenTata', tokenTata.data);
return tokenTata.data?.access_token
}
// 获取 ticket
async function handleTicKetData(accessToken) {
let ticketUrl = `https://api.weixin.qq.com/cgi-bin/ticket/handleTicKet?access_token=${accessToken}&type=jsapi`;
let ticketData = await axios.get(ticketUrl);
console.log('ticketData', ticketData.data);
return ticketData.data?.ticket
}
// 保存 access_token、ticket 数据
async function createTicket(access_token, ticket) {
let time = new Date().getTime();
await new ticketModel({
access_token,
token_time: time,
ticket,
ticket_time: time
}).save().then(res => {
console.log('createTicket-res', res);
})
}
// 更新 access_token、ticket 数据
async function updateTicket(_id, access_token, ticket) {
let time = new Date().getTime();
await ticketModel.update({ _id }, {
access_token,
token_time: time,
ticket,
ticket_time: time
})
}
// 处理 access_token 和 ticket
async function handleTicKet() {
let access_token = '';
let ticket = '';
const ticKetData = await ticketModel.find() ?? [];
// 判断数据库是否存储过ticket
if (ticKetData.length > 0) {
let t = new Date().getTime() - ticKetData[0].token_time;
if (t > 7000000) { //是否过期
//重新获取
await loadData();
console.log('过期后重新获取token', access_token)
console.log('过期后重新获取ticket', ticket)
// 准备更新数据
let { _id } = ticKetData[0];
await updateTicket(_id, access_token, ticket)
} else {
access_token = ticKetData[0].access_token;
ticket = ticKetData[0].ticket;
console.log('从数据库获取: token', access_token)
console.log('从数据库获取: ticket', ticket)
}
} else {
// 生成Ticket信息,注意这里生成的Ticket信息可能有误,如:access_token 或者 ticket 为空 。 此时,需要保证 appid、secret和公众号的相关配置正确, 如果生成的数据有误,删除数据后在重新生成
// 生成Ticket信息
await loadData();
// 第一次获取access_token,对数据库进行新增操作
await createTicket(access_token, ticket)
}
// 生成Ticket信息
async function loadData() {
access_token = await getAccessToken()
ticket = await handleTicKetData(access_token)
}
return {
access_token,
ticket
}
}
// 生成签名
function generateJSSDKSignature(timestamp, nonceStr, url, jsapiTicket) {
const rawString = `jsapi_ticket=${jsapiTicket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`;
const signature = crypto.createHash('sha1').update(rawString).digest('hex');
return signature;
}
// 生成wx.config的入参数
async function getWxConfigParams(url) {
const { ticket } = await handleTicKet()
const obj = {
jsapi_ticket: ticket,
nonceStr: createNonceStr(),
timestamp: createTimestamp(),
url
}
// 生成签名, 参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。
let signature = generateJSSDKSignature(obj.timestamp, obj.nonceStr, url, ticket)
obj.signature = signature;
obj.appId = appid;
return obj;
}
module.exports = {
getWxConfigParams,
handleTicKet
};
完整代码
https://gitee.com/ironc/wx-js-sdk-demo
常见问题
1、config:fail,invalid url domain
当前网页所使用的域名,没有在JS接口安全域名
中,参考公众号配置
中的 JS接口安全域名
进行修改
2、config:fail,invalid signature
签名失败,注意签名的参数为 jsapi_ticket、nonceStr、timestamp、url,url为当前页面对应的域名。
提供一个签名方法(记得安装一下crypto):
// npm i crypto
function generateJSSDKSignature(timestamp, nonceStr, url, jsapiTicket) {
const rawString = `jsapi_ticket=${jsapiTicket}&noncestr=${nonceStr}×tamp=${timestamp}&url=${url}`;
const signature = crypto.createHash('sha1').update(rawString).digest('hex');
return signature;
}
3、iOS微信浏览器中window下不存在 wx
属性
切换一个JS-SDK的版本,我使用的是 http://res.wx.qq.com/open/js/jweixin-1.6.0.js
, 发现的该问题。
解决方式:
1、使用其他版本的JS链接,比如:https://res.wx.qq.com/open/js/jweixin-1.3.2.js
,需要注意您所需要的SDK的功能与版本是否匹配
2、使用npm安装, npm install weixin-js-sdk
, npm地址 https://www.npmjs.com/package/weixin-js-sdk
❝
二选一即可
❞
相关工具
1、花生壳
https://hsk.oray.com/download/
2、natapp
https://natapp.cn/
3、免费mongodb (其云服务免费)
https://www.mongodb.com/
原文始发于微信公众号(WEB大前端):JS-SDK鉴权流程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/225408.html