四、全局票据
全局票据需要基于mongodb或者redires,我们用mongodb。
新建个mongoose.js
const mongoose = require('mongoose') const { Schema } = mongoose mongoose.connect('mongodb://localhost:27017/weixin', { useNewUrlParser: true }, () => { console.log('Mongodb connected..') }) exports.ServerToken = mongoose.model('ServerToken', { accessToken: String });
index.js里改造上面用co-wechat-api的:
const { ServerToken } = require('./mongoose')//全局票据来源 const WechatAPI = require('co-wechat-api') const api = new WechatAPI( conf.appid, conf.appsecret, // 取Token async () => await ServerToken.findOne(), // 存Token async token => await ServerToken.updateOne({}, token, { upsert: true }) ) router.get('/getFollowers', async ctx => { let res = await api.getFollowers() res = await api.batchGetUsers(res.data.openid, 'zh_CN') ctx.body = res })
再在index.html中加上一个按钮和一个按钮点击方法:
<cube-button @click='getFollowers'>getFollowers</cube-button>
async getFollowers(){ const res = await axios.get('/getFollowers') console.log('res',res) },
动动小手点击一下:(这个getFollwers拿到了数据)
五、消息推动
就类似于这个,手机微信扫码微信公众平台前台发送1或者2,饼图自动统计1和2发送的次数。
后台(模拟器)会显示前台(手机微信在测试订阅号)的推送,而且更新echart。
代码为下面的vote部分,后面会放出代码。
六、Oauth2认证流程
首先要知道有三个端,浏览器,服务器,微信服务器。
1.浏览器向服务器发送认证请求
2.服务器让浏览器重定向微信认证界面
3.浏览器向微信服务器请求第三方认证(微信认证)
4.微信服务器毁掉给服务器一个认证code
5.服务器用code向微信服务器申请认证令牌
6.微信服务器返给服务器一个令牌
最后当服务器得到令牌认证成功后,发给浏览器一个指令,刷新界面
刷新后就会有一个用户信息
使用微信开发者工具,选择公众号网页,用来预览。
PS:以上代码中
- 消息推动我放在vote目录了
- 剩余的api调用方法放在了seed目录
七、实现一个微信认证登录
配置js接口安全域名,就是我们转发的公网域名(不用带协议):zhifieji.vipgz4.idcfengye.com
再就是每个微信接口api那里也要授权域名,即下图的修改位置,修改的和上面一样:(zhifieji.vipgz4.idcfengye.com)
把前面的项目中seed目录拷贝一份叫做seed_up,我们给予前面的在seed_up中继续干!
index.js;
const OAuth = require('co-wechat-oauth')//引入一个oauth库 const oauth = new OAuth(conf.appid,conf.appsecret) /** * 生成用户URL */ router.get('/wxAuthorize', async (ctx, next) => { const state = ctx.query.id console.log('ctx...' + ctx.href) let redirectUrl = ctx.href redirectUrl = redirectUrl.replace('wxAuthorize', 'wxCallback') const scope = 'snsapi_userinfo' const url = oauth.getAuthorizeURL(redirectUrl, state, scope) console.log('url' + url) ctx.redirect(url) }) /** * 用户回调方法 */ router.get('/wxCallback', async ctx => { const code = ctx.query.code console.log('wxCallback code', code) const token = await oauth.getAccessToken(code) const accessToken = token.data.access_token const openid = token.data.openid console.log('accessToken', accessToken) console.log('openid', openid) ctx.redirect('/?openid=' + openid) }) /** * 获取用户信息 */ router.get('/getUser', async ctx => { const openid = ctx.query.openid const userInfo = await oauth.getUser(openid) console.log('userInfo:', userInfo) ctx.body = userInfo })
index.html:
<!DOCTYPE html> <html> <head> <title>全栈开发微信公众号</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0"> <script src="https://unpkg.com/vue@2.1.10/dist/vue.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://unpkg.com/cube-ui/lib/cube.min.js"></script> <script src="https://cdn.bootcss.com/qs/6.6.0/qs.js"></script> <script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script> <link rel="stylesheet" href="https://unpkg.com/cube-ui/lib/cube.min.css"> <style> /* .cube-btn { margin: 10px 0; } */ </style> </head> <body> <div id="app"> <cube-input v-model="value"></cube-input> <cube-button @click='click'>Click</cube-button> <cube-button @click='getTokens'>getTokens</cube-button> <cube-button @click='getFollowers'>getFollowers</cube-button> <cube-button @click='auth'>微信登录</cube-button> <cube-button @click='getUser'>获取用户信息</cube-button> </div> <script> var app = new Vue({ el: '#app', data: { value: 'input' }, methods: { click: function () { console.log('click') }, async getTokens(){ const res = await axios.get('/getTokens') console.log('res:',res) }, async getFollowers(){ const res = await axios.get('/getFollowers') console.log('res',res) }, async auth(){ window.location.href = '/wxAuthorize' }, async getUser(){ const qs = Qs.parse(window.location.search.substr(1)) const openid= qs.openid const res = await axios.get('/getUser',{ params:{ openid } }) console.log('res',res) } }, mounted: function () { }, }); </script> </body> </html>
全局票据(一样用到mongoose,从上次的修改)
mongoose.js:
const mongoose = require('mongoose') const { Schema } = mongoose mongoose.connect('mongodb://localhost:27017/weixin', { useNewUrlParser: true }, () => { console.log('Mongodb connected..') }) exports.ServerToken = mongoose.model('ServerToken', { accessToken: String }); //以下为seed_up新增 schema = new Schema({ access_token: String, expires_in: Number, refresh_token: String, openid: String, scope: String, create_at: String }); // 自定义getToken方法 schema.statics.getToken = async function (openid) { return await this.findOne({ openid: openid }); }; schema.statics.setToken = async function (openid, token) { // 有则更新,无则添加 const query = { openid: openid }; const options = { upsert: true }; return await this.updateOne(query, token, options); }; exports.ClientToken = mongoose.model('ClientToken', schema);