1.微信公众号 消息对话实现
- mp.weixin.qq.com 扫描登录
- 首页点击 web开发者工具
- 绑定开发者自己的手机号
- 安全中心-设置自己服务器的白名单ip
- 首页-基本配置-获取AppID和 AppSecret
- 开发者工具- 公众号平台测试账号 设置 url和token
- 关注公众号:微信公众平台测试号,进行消息发送测试
验证微信接口配置的逻辑 (加密算法的逻辑)
其实整个过程可以直接返回微信给的echostr,不需要加密校验。验证加密只是安全考虑(防止非微信的第三方攻击服务器,或者爬虫)
整个过程是:服务器验证微信是否安全。
1.验证代码实现
实现代码1(记得使用80端口)
//conf.js
module.exports = {
appid:'xxxxx',
appsecret:'xxxxx',
token:'kaikeba',
}
//index.js
const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const xml2js = require('xml2js')
const app = new Koa()
const url = require('url')
const conf = require('./conf')
const crypto = require('crypto')
const xmlParser = require('koa-xml-body')
app.use(xmlParser())//每次接口返回都会,自动把xml格式转化为json
const router = new Router()
app.use(static(__dirname + '/'))
// 验证
router.get('/wechat', ctx => {
console.log('微信认证...', ctx.url)
const {
query
} = url.parse(ctx.url, true)
const {
signature, // 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp, // 时间戳
nonce, // 随机数
echostr // 随机字符串
} = query
console.log('wechat', query)
// 将 token timestamp nonce 三个参数进行字典序排序并用sha1加密
let str = [conf.token, timestamp, nonce].sort().join('');
console.log('str', str)
let strSha1 = crypto.createHash('sha1').update(str).digest('hex');
console.log(`自己加密后的字符串为:${strSha1}`);
console.log(`微信传入的加密字符串为:${signature}`);
console.log(`两者比较结果为:${signature == strSha1}`);
// 签名对比,相同则按照微信要求返回echostr参数值
if (signature == strSha1) {
ctx.body = echostr
} else {
ctx.body = "你不是微信"
}
})
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(80);
2.实现后台代码二 使用co-wechat工具
const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const bodyParser = require('koa-bodyparser');
const app = new Koa()
const conf = require('./conf')
app.use(bodyParser())
const router = new Router()
app.use(static(__dirname + '/'))
const axios = require('axios')
const crypto = require('crypto')
const wechat = require('co-wechat')
//这里同时做了:验证 + 接受消息返回内容处理,通过中间件实现
router.all('/wechat', wechat(conf).middleware(
async message => {
console.log('wechat:', message)
return 'Hello World ' + message.Content
}
))
测试方式:
-
开发者工具- 公众号平台测试账号 设置 url和token 点击提交测试
-
注意首页-接口权限,对应的接口权限是否有打开
高级api使用
- 获取token
- 调用微信的接口
1.自己管理token
const tokenCache = {
access_token: '',
updateTime: Date.now(),
expires_in: 7200,
};
//获取token
router.get('/getTokens', async ctx => {
const wxDomain = `https://api.weixin.qq.com`;
const path = `/cgi-bin/token`;
const params = `?grant_type=client_credential&appid=${conf.appid}&secret=${conf.appsecret}`;
const url = `${wxDomain}${path}${params}`;
const res = await axios.get(url);
Object.assign(tokenCache, res.data, {
updateTime: Date.now()
});
ctx.body = res.data
})
//获取对应的ip地址列表 注意如果没有权限的接口不用乱掉
router.get('/getcallbackip',async ctx => {
const url = `https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=${tokenCache.access_token}`
const res = await axios.get(url)
console.log('getcallbackip:',res)
ctx.body = res.data
})
2.使用co-wechat-api库实现请求拦截 与token设置判断
const WechatAPI = require('co-wechat-api');//通过第三方工具 管理token
const { ServerToken} = require('./mongoose')
const api = new WechatAPI(conf.appid, conf.appsecret);
//获取对应的ip地址列表
router.get('/getcallbackip', async ctx => {
var res = await api.getIp();
console.log('res', res)
ctx.body = res
})
测试:
- 运行node index.js
- http://127.0.0.1:3000/getTokens
- http://127.0.0.1:3000/getcallbackip
全局票据
原因
- token接口请求有次数限制
- 多服务器部署时,各个服务器各自生成token
解决
使用 持久化:mongodb 或 redis
//mongoose.js
const mongoose = require('mongoose')
const {
Schema
} = mongoose
mongoose.connect('mongodb://username:pwd@81.71.143.xxx:27017/weixin?authSource=admin', {
useNewUrlParser: true
}, () => {
console.log('Mongodb connected..')
})
exports.ServerToken = mongoose.model('ServerToken', {
accessToken: String
});
//index.js
const api = new WechatAPI(
conf.appid,
conf.appsecret,
// 取Token
async () => await ServerToken.findOne(),//根据数据库
// 存Token
async token => await ServerToken.updateOne({}, token, { upsert: true })
)
2. Oauth交互流程
- 基本配置-服务器配置 设置对应的服务器验证
- 打开微信开发者工具 进行调试
- 注意一般订阅号是没有权限,需要认证-企业资质
1.服务器验证地址
2.Oauth交互流程
后台代码
const OAuth = require('co-wechat-oauth')
const oauth = new OAuth(conf.appid, conf.appsecret
,
async function (openid) {
return await ClientToken.getToken(openid)
},
async function (openid, token) {
return await ClientToken.setToken(openid, token)
}
)
/**
* 生成用户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)
})
3. 调用原生设备的api
相关代码
后台代码
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('/getJsConfig',async ctx => {
console.log('getJSSDK...',ctx.query)
const res = await api.getJsConfig(ctx.query)
ctx.body = res
})
前端代码
<script src="js/jweixin-1.4.0.js"></script>
//对应方法
async getJSConfig() {
console.log('wx', wx)
const res = await axios.get('/getJSConfig', {
params: {
url: window.location.href
}
})
console.log('res....', res.data)
res.data.jsApiList = ['onMenuShareTimeline', 'onMenuShareAppMessage']
wx.config(res.data);
wx.ready(function () {
console.log('wx.ready......')
})
wx.getNetworkType({
success: function (res) {
// 返回网络类型2g,3g,4g,wifi
var networkType = res.networkType;
console.log('getNetworkType...', networkType)
}
})
}