- 申请公众号(服务号+已认证)
- web开发者工具中绑定开发人员(该开发人员需要关注1中申请的公众号)
- 基本配置
3.1 服务器配置
URL:验证服务器(后端写的验证服务器的接口)
后端代码:egg.js
yarn add crypto-js
const SHA1 = require('crypto-js/sha1');
async checkSign() {
const { ctx, app } = this;
const token = app.config.wechat_config.token; // 替换为你的微信公众号的Token
const { signature, timestamp, nonce, echostr } = ctx.query;
const shasum = SHA1([ token, timestamp, nonce ].sort().join('')).toString();
if (shasum === signature) {
return echostr;
}
return 'Invalid signature';
}
async validate() {
const { ctx, service } = this;
ctx.body = await service.wx.checkSign();
}
Token: 可以自定义(后续跟微信要信息的时候使用,验证服务器的时候也需要)
服务器配置什么时候启用:
一些自定义的跟微信相关的操作:例如支付流程,自定义推送等
3.2 自定义菜单(公众号底部的菜单配置)
3.2.1 可以配置完成的带公众号基础信息的url
例如:https://open.weixin.qq.com/connect/oauth2/authorize? appid=wx8a432443c4997c0c&redirect_uri=http://gzh-dev.nangaoyun.com/equip/wechatAuth/menu?type=work&response_type=code&scope=snsapi_userinfo&state=123&connect_redirect=1#wechat_redirect
3.2.2 也可配置访问页面的地址
例如:http://www.youtianchen.cn
- 网页授权
4.1 用户同意授权,获取token
这个code是我们点击自定义菜单时,微信内部重定向到一个url,这个url里带了code
获取code(前端代码)
import { history } from "umi";
import { doFetch } from "./doFetch"; //发送请求的方法,封装了一下而已
//从网页地址中获取code
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
return false;
}
export default function getUserinfo(props, fn) {
const token = localStorage.getItem("TOKENS");
if (token && token != "undefined") {
return;
}
const code = getQueryVariable("code");
if (code) {
alert(code);
//获取access_token
doFetch({
url: "http://www.youtianchen.cn/web/authtoken",
params: {
code,
},
}).then((res) => {
console.log('====================================');
console.log(res);
console.log('====================================');
});
} else {
let uri = "http://www.youtianchen.cn"; //'http://www.sanbaodagong.com/wechat/index.html';
window.location.href =
"https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx289794cd442ff592&redirect_uri=" +
uri +
"&response_type=code&scope=snsapi_base#wechat_redirect";
}
}
4.2 前端拿到code传给后端,后端获取access_token(这个可以做各系统的绑定)
后端这里给出egg.js写出的代码:
// 判断token值从哪里获取
async fetchAccessToken(code) {
const { app } = this;
const access_token = await app.redis.get('access_token');
console.log(access_token, 'access_token');
// redis 存在access_token
if (!access_token) {
const token = await this.fetchToken(code);
return token;
}
// redis不存在access_token
const istoken = await this.istoken(access_token);
if (istoken) {
return access_token;
}
const token = await this.fetchToken(code);
return token;
}
// 判断token是否失效
async istoken(token) {
const { ctx, app } = this;
const openid = await app.redis.get('openid');
const res = await ctx.curl(
`https://api.weixin.qq.com/sns/auth?access_token=${token}&openid=${openid}`,
{
// 必须指定 method
method: 'GET',
dataType: 'json',
}
);
console.log(res, 'istoken');
return res?.data?.errcode === 0;
}
// 获取token 定时任务
async fetchToken(code) {
const { ctx, app } = this;
const appid = app.config.wechat_config.appid;
const appsecret = app.config.wechat_config.appsecret;
const refresh_token = await app.redis.get('refresh_token');
const URL = code
? `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${appsecret}&code=${code}&grant_type=authorization_code`
: `https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=${appid}&grant_type=refresh_token&refresh_token=${refresh_token}`;
const res = await ctx.curl(URL, {
method: 'GET',
dataType: 'json',
});
console.log(res, 'token_response');
if (res.data.refresh_token) {
await app.redis.set('refresh_token', res.data.refresh_token);
}
if (res.data.openid) {
await app.redis.set('openid', res.data.openid);
}
if (res.data.access_token) {
await app.redis.set('access_token', res.data.access_token);
await this.createMenu(res.data.access_token);
return res.data.access_token;
}
return null;
}
4.3 后端拿到access_token可以生成签名
后端这里给出egg.js写出的代码:
// 判断ticket值从哪里获取
async getAccessTicket() {
const { app } = this;
const ticket = await app.redis.get('ticket');
// redis 存在ticket
console.log(ticket, 'ticket');
if (!ticket) {
const res = await this.getTicket();
return res;
}
// redis 存在ticket
return ticket;
}
// 获取ticket 定时任务
async getTicket() {
const { ctx, app } = this;
const access_token = await this.fetchAccessToken();
console.log(access_token, '换key');
const res = await ctx.curl(
`https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`,
{
// 必须指定 method
method: 'GET',
dataType: 'json',
}
);
console.log(res, 'ticket_response');
if (res.data.ticket) {
await app.redis.set('ticket', res.data.ticket);
return res.data.ticket;
}
return null;
}
- JS-SDK
yarn add weixin-js-sdk
5.1 公众号设置-功能设置
5.1.1 js接口安全域名配置
代码所在的服务器配置访问页面的url,例如:
访问页面地址如下:
http://gzh-test.nangaoyun.com/quality/#/welcome
那 js接口安全域名配置:http://gzh-test.nangaoyun.com/quality
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/quality指向的文件夹下
访问页面地址如下:
http://gzh-test.nangaoyun.com/plan/#/welcome
那 js接口安全域名配置:http://gzh-test.nangaoyun.com/plan
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/plan指向的文件夹下
以上我们看到访问地址在服务器的配置在同一个根目录下
因此可以只配置一个js接口安全域名:http://gzh-test.nangaoyun.com
需要把MP_verify_dPqSolp0G3VuCs9n.txt放在服务器http://gzh-test.nangaoyun.com/quality指向的文件夹下
//和http://gzh-test.nangaoyun.com/plan指向的文件夹下共同的根目录下面即可;
例如目录结构是这样的:
5.2 调用微信的一些功能,以下以扫码为例(前端代码)
//写一个公共方法:wxConfig
import { doFetch } from "./doFetch";
import { Toast } from "antd-mobile";
import wx from 'weixin-js-sdk';
export default async function (url) {
let res = await doFetch({ url: '/pengli-wx/equip/common/jsSdk', params: { locUrl: url } });
if (res?.code === 1) {
let wxconfig = res?.jsSdk ?? {}
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: wxconfig?.appId, // 必填,公众号的唯一标识
timestamp: wxconfig?.timeStamp, // 必填,生成签名的时间戳
nonceStr: wxconfig?.nonceStr, // 必填,生成签名的随机串
signature: wxconfig?.signature,// 必填,签名
jsApiList: [
'scanQRCode'
] // 必填,需要使用的JS接口列表
});
wx.ready(function () {
Toast.show({
icon: 'success',
content: '成功',
})
});
wx.error(function (res) {
Toast.show({
icon: 'error',
content: res.errMsg,
})
});
}
}
按钮点击扫码:
async() => {
await wxConfig(document.URL)
wx.scanQRCode({
needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
}
});
}
**
PS: access_token和签名都是2小时过期
**