最近做需求要对接微信公众号,看了两天文档,基本算是理清楚了,在这里做下记录。
准备工作
了解公众号类型和接口权限
微信公众号分为订阅号
和服务号
,两种账号都可以进行微信认证以获取更多接口权限(个人注册的订阅号不能进行微信认证)。
具体接口权限见:官方文档 >>
获取微信公众平台测试号
如果没有申请好的公众号,可以使用官方提供的测试账号,使用自己微信号扫描登录即可。
登录地址:微信公众平台测试号 >>
网页授权回调域名设置
我们要想在我们的网页中获取用户信息,就必须通过网页授权来实现。网页回调域名是指获取用户信息后需要跳转的域名地址,因为获取用户信息是微信提供的链接,获取后需要再重定向到我们自己的页面。
使用之前需要到公众号里把我们的域名设置成网页授权域名。
设置方法:登录微信公众平台 > 设置 > 公众号设置 > 功能设置 > 网页授权域名
配置规范为全域名(不需要加
http://
或https://
),设置后可以在该域名下所有的页面使用,但不能在该域名的二级域名下使用。
如:设置了
www.raydom.wang
,http://www.raydom.wang/index.html
中可以使用,但http://note.raydom.wang
中不能使用。
后台环境搭建
为了安全起见,微信的接口调用都需要放到后台进行。这里使用的是基于node环境的koa2服务环境。
开始
第一步:用户同意授权,获取code
引导用户打开如下链接:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
参数说明:
参数 | 必填 | 说明 |
---|---|---|
appid | 是 | 公众号的唯一标识 |
redirect_uri | 是 | 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
注意:redirect_uri 的值需要经过 urlEncode 处理。
js中没有提供原生方法,可以使用工具处理以后使用: urlEncode处理工具 >>
如果用户关注了公众号,
scope
使用snsapi_userinfo
获取用户信息时,也不会弹出授权框(测试公众号每次都会弹)
第二步:通过code获取用户信息
跳转到我们自己的页面以后,url中会自动添加code。
示例:http://test.raydom.wang/?code=081tRRYX1Bk2IT0JNqVX16RAYX1tRRYT&state=123
获取url中的code到后台
前端代码示例:
// 获取url中的参数
function GetQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
// 这里使用的axios进行ajax请求
axios.get("http://testapi.raydom.wang/login", {
params: {
code: GetQueryString("code")
}
})
.then((res) => {
console.log(res)
})
- 在后台用拿到的
code
获取ACCESS_TOKEN
、openid
和更多信息
后台代码示例:
const router = require('koa-router')() // 引入router
const superagent = require('superagent') // 一个node环境http(s)请求中间件
const cache = require('memory-cache') // 缓存处理中间件
const appid = "xxxxxxxxxxxxxxx" // appid
const appsecret = "xxxxxxxxxxxxxxxxxxx" // appsecret
router.get("/login", async(ctx, next) => {
let ACCESS_TOKEN = "",
openid = "";
// 使用code获取openid和access_token
await superagent
.get("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +
appid + "&secret=" +
appsecret + "&code=" +
ctx.query.code + "&grant_type=authorization_code")
.then(res => {
// 此处本来应该用res.body获取返回的json数据,但总是获取不到,只能用text代替
let result = JSON.parse(res.text)
ACCESS_TOKEN = result.access_token
openid = result.openid
})
.catch(res => {
console.log(res)
})
// 使用ACCESS_TOKEN和openid
await superagent
.get("https://api.weixin.qq.com/sns/userinfo?access_token=" +
access_token + "&openid=" + openid + "&lang=zh_CN")
.then(res => {
console.log(JSON.parse(res.text))
ctx.body = {
state: 1,
msg: '获取access_token成功!'
}
})
.catch(res => {
console.log(res)
})
})
- 刷新access_token(如果需要)
由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。
请求方法:
获取第二步的refresh_token后,请求以下链接获取access_token:https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
返回结果:
参数 | 描述 |
---|---|
access_token | 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 |
expires_in | access_token接口调用凭证超时时间,单位(秒) |
refresh_token | 用户刷新access_token |
openid | 用户唯一标识 |
scope | 用户授权的作用域,使用逗号(,)分隔 |
关于UnionID机制(测试账号无法获取)
如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为同一用户,对同一个微信开放平台下的不同应用(移动应用、网站应用和公众帐号),unionid是相同的。
获取
unionid
需要scope
使用snsapi_userinfo
。
检验授权凭证(access_token)是否有效
请求接口:http:GET(请使用https协议) https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID
有效返回的JSON结果:
{ "errcode":0,"errmsg":"ok"}
错误时的JSON返回示例:
{ "errcode":40003,"errmsg":"invalid openid"}