套用《围城》里老学究的的一句开场白:"兄弟我刚入行的时候…“兄弟我是很不喜欢微信这样一款应用的——尽管我在2011年就已经是微信的注册用户。在我看来,第一个,能用qq达到的目的为什么还要微信?其次,凭什么一个开发要绑在一款微信里?但是,周边的人似乎在我毕业的前后通通用上了微信。
我的第一个老板,也非常喜欢微信。她给我第一份工作,就是运营一个微信公众号,持续至今。
我上一个老板,则给我安利了一部叫《创业时代》的商战电视剧。讲的就是另外一条平行世界线里,一款类似微信的语音即时通讯软件创业的故事。
这大概是2007年之后影响我最大的电视剧——尽管这部电视剧只有6分多的评分,尽管我2007年之后没看过电视剧。
扯远了。
本文延续上一讲的程序进行实验。需要安装微信web开发工具。
官方资料 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 npm库 https://github.com/node-webot/wechat-oauth 阮一峰的OAuth2 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
网页授权原理:
(A)用户访问客户端,客户端将前者导向认证服务器。
(B)用户选择是否给客户端授权
(C)如果用户授权,认证服务器将用户导向客户端指定的重定向uri(redirection URI),同时附上授权码
(D)客户端收到授权码,附上之前的重定向uri,向认证服务器申请令牌,
(E)认证服务器核对了授权码和URi,向客户端发送令牌包括访问令牌(access_token)和更新令牌(refresh_token)。
微信做auth2.0认证需要以下信息:
在此处配置你的域名:
配置JS安全接口:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
注意,这里的配置域名都不需要加http://,后面也不能带/
调用第三方服务器接口—>导向到微信服务器认证—>第三方认证—>成功后回调微信code。
需要引入一个新的co-wecaht-oauth
库。
首先我们写一个前端请求方法。比如说,我点击一个按钮,跳转到一个/wxAuthorize
下的微信认证页面。然后成功了的话,跳转回/wxCallback
那么后端就要写一个路由:
// index.js
const const Oauth=require('co-wechat-oauth');
const oauth=new Oauth(config.appid,config.appsecret);
router.get('/wxAuthorize', async (ctx, next) => {
//重定向到微信界面
const state = ctx.query.id;
// const target = ctx.href
console.log('ctx...' + ctx.href);
// 目标地址
let redirectUrl = ctx.href;
redirectUrl = redirectUrl.replace('wxAuthorize', 'wxCallback')
const scope = 'snsapi_userinfo'
// 导向微信认证页面
var url = oauth.getAuthorizeURL(redirectUrl, state, scope);
console.log('url' + url)
ctx.redirect(url)
})
跳转的接口写一下:
router.get('/wxCallback',async (ctx, next) => {
const code = ctx.query.code
console.log('callback:', code)
const token=await oauth.getAccessToken(code);
const access_token=token.data.access_token;
const openid=token.data.openid;
console.log(token);
// 接着让丫跳转到一个认证后的界面:带上openid
})
点击用户登录按钮:
同意之后就跳转了wxCallback,还有了一个授权码:
现在我就完成了第一步功能。
认证完了。有了access_token和openid,就可以肆意搞起来了。
微信用户的公开信息包括:
router.get('/authed',async (ctx,next)=>{
再执行流程:
用户信息就拿到了。
openid对于前端来说是没有用的。真正需要的其实是后端。如果一个后端老是要你发openID给他,那就是他的问题了。因此上面的例子是把openid放到链接里。其实是不合理的。
这里的access_token是和服务器端的access_token不太一样,服务器端的只需要一个就好了。但是网页端的。每个用户登录都会产生一个token。
还是得存在mongodb里。
修改mongoose.js,添加如下内容:
// ClientAccessToken
schema = new Schema({
access_tokeåån: 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);
上面这一段添加了两个方法:查询和更新。
然后在new出Oauth的时候调用这两个方法:
const { ServerToken, ClientToken } = require('./mongoose');
const Oauth = require('co-wechat-oauth');
const oauth = new Oauth(
config.appid,
config.appsecret,
async function (openid) {
return await ClientToken.getToken(openid)
},
async function (openid, token) {
return await ClientToken.setToken(openid, token)
}
);
好了。你每次登录之后,就产生了一个token存到了mongo的clienttoken表里了。如果你要调用,就可以使用ClientToken.getToken(openid)
获取。
官方资料:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 npm库: https://github.com/node-webot/co-wechat-api
所谓微信JS-SDK,就是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。node操作这个,已经有封装好的调用了,就是上一讲的co-wechat-api。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
简单说,网页想调用设备端的一些特性?微信帮你做。前提是获得授权。这个过程是微信认证我们开发的网页。
微信给前端的设备能力(扫码可看):
我们看文档:
首先是配置jssdk,然后是引入js文件http://res.wx.qq.com/open/js/jweixin-1.4.0.js(前两步已做),会生成一个wx对象。接下来就是在前端做配置:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
问题在于,这些乱七八糟的东西前端都没有。
写一个请求方法和接口:
// 前端
const res=await axios.get('/getJsConfig',{
params:{
//把你的url参数带上!
url:window.location.href
}
});
console.log(res.data)
//后端
router.get('/getJsConfig', async ctx => {
console.log('getJSSDK...', ctx.query)
var res = await api.getJsConfig(ctx.query);
console.log('res', res)
ctx.body = res
})
拿到配置后,我们继续修改前端要让网页拿到onMenuShareTimeline
和onMenuShareAppMessage
的授权:
res.data.jsApiList = ['onMenuShareTimeline', 'onMenuShareAppMessage']
wx.config(res.data);
wx.ready(function (e) {
console.log('wx.ready......',e)
});
jsApiList参考 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 附录2
在微信开发者工具上看到:
接口就申请成功了。
现在一个乙方给你一个任务:我要做一个科学算命的应用。需要分享之后才能看到结果。应该怎么搞?
首先是点击get一个路由/test_wxAuthorize
,登录后跳转share.html
router.get('/test_wxAuthorize', async (ctx, next) => {
const state = ctx.query.id;
// 目标地址
let redirectUrl = ctx.href;
redirectUrl = redirectUrl.replace('wxAuthorize', 'share.html')
const scope = 'snsapi_userinfo'
// 导向微信认证页面
var url = oauth.getAuthorizeURL(redirectUrl, state, scope);
ctx.redirect(url)
});
然后让他跳转到test_share.html:
router.get('/test_wxAuthorize', async (ctx, next) => {
const state = ctx.query.id;
// 目标地址
let redirectUrl = ctx.href;
redirectUrl = redirectUrl.replace('wxAuthorize', 'share.html')
const scope = 'snsapi_userinfo'
// 导向微信认证页面
var url = oauth.getAuthorizeURL(redirectUrl, state, scope);
ctx.redirect(url)
});
写下这个页面吧:
<!--test_share.html-->
<html>
<head>
<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">
<div>右上角分享到朋友圈后看答案</div>
<p>我家的mbp提供云计算服务</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
value: 'input'
},
methods: {
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);
}
},
mounted: async function () {
//用户信息
const code = this.getQueryVariable('code');
let userInfo=await axios.get(`/userInfo?code=${code}`);
userInfo=userInfo.data;
//测试结果
const _res = await axios.get('/getTest')
let num = _res.data;
// 获取配置
const res = await axios.get('/getJsConfig', {
params: {
url: window.location.href
}
})
// jssdk权限:分享给朋友,分享给个人
res.data.jsApiList = ['onMenuShareTimeline', 'onMenuShareAppMessage']
wx.config(res.data);
wx.ready(function (e) {
console.log('wx.ready......', e)
let conf = {
title: `震惊!原来${userInfo.nickname}的命运是这样的...`, // 分享标题
link: 'http://djtao.free.idcfengye.com/test_wxAuthorize', // 分享链接
imgUrl: userInfo.headimgurl, // 分享图标
success: async function () {
window.location.href = `/server/${num}.html`
}
}
wx.onMenuShareTimeline(conf)
});
},
});
</script>
</body>
</html>
我曾经无聊爬取了51支签及其解读(html)格式,分为1-51.html在server文件夹下,刚好可以用来求签。
补充接口:
router.get('/test_wxAuthorize', async (ctx, next) => {
const state = ctx.query.id;
// 目标地址
let redirectUrl = ctx.href;
redirectUrl = redirectUrl.replace('wxAuthorize', 'share.html')
const scope = 'snsapi_userinfo'
// 导向微信认证页面
var url = oauth.getAuthorizeURL(redirectUrl, state, scope);
ctx.redirect(url)
});
//科学算命核心接口
router.get('/getTest',async (ctx,next)=>{
var num=Math.round(Math.random()*51);
// let data=fs.readFileSync(`server/${num}.html`)
// console.log(data);
ctx.body=num;
})
那么功能就完成了。
这种病毒式应用要少搞,搞了会封号的。