引言
最近在写微信公众号的后端,写完了要测试一下,但是前端还没人弄,我就先弄一弄搞一下测试。 第一步就是用户授权登录了
Oauth2
微信公众号授权,微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
step1
首先就是要在微信公众平台后台控制那里做一些设置(2018-09-17)
-
在左边菜单栏里点击 “接口权限”, 会看到很多的接口选项,我们点击如下图 ’修改‘
-
然后会进入到下面这个界面
我们就选择 “网页授权域名” 的设置
3.将你要微信域名填进入
这里有一些认证什么的很简单了就不说了,照着上面写的来就行
这样就算完成了准备工作
step2(前端)
前端的部分相当的少
// 无论什么手段,让用户跳转到微信指定的url就行了 只是需要解释一下这个url的参数
<a href="https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect"/>
参数 ------是否必须-------说明
appi:------(是)--------------公众号的唯一标识
redirect_uri:(是)授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
response_type:(是) 返回类型,请填写code
scope:(是)应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
state:(否) 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect:(是) 无论直接打开还是做页面302重定向时候,必须带此参数
用户在微信内打开这个网页的时候,就会弹窗询问 ****(你的公众号)需要你的授权,得到你的头像,昵称等信息, 然后用户点击同意, 微信就会重定向到你说填写的那个回调链接地址,顺便把code
code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
作为query参数给你.redirect_uri/?code=CODE&state=STATE
这时候前端就只需要把这个code作为参数,去请求后端的接口就行了。 完事儿!
step3(后端)
后端我封装了几个api,分别是获取用户access_token,用户信息,刷新access_token
/**
* 获取用户信息
* @param accessToken 微信用户凭证
* @param openId 微信用户id
*/
export const getWeChatUserInfo = async (accessToken: string, openId: string) => {
let apiUrl = config.weChatApi003.replace('ACCESS_TOKEN', accessToken).replace('OPENID', openId);
let ret = await get(apiUrl);
if (!ret) {
throw userErrorHandler.find('errcode', 405);
}
if (ret.body) {
ret = ret.body.toString();
ret = JSON.parse(ret);
}
if (ret && (ret.errcode || !ret.nickname)) {
throw userErrorHandler.find('errcode', 402);
}
return ret;
};
/**
* 获取用户accessToken
* @param code 获取用户accessToken的临时code
*/
export const getAccessToken = async (code: string) => {
let apiUrl = config.weChatApi001.replace('APPID', config.GZH.appId).replace('SECRET', config.GZH.secret).replace('CODE', code);
let ret: any = await get(apiUrl);
if (!ret) {
throw userErrorHandler.find('errcode', 405);
}
if (ret.body) {
ret = ret.body.toString();
ret = JSON.parse(ret);
}
if (ret && (ret.errcode || !ret.access_token)) {
throw userErrorHandler.find('errcode', 401);
}
return ret;
};
/**
* 刷新用户accessToken
* @param refreshToken 用于刷新accessToken的字符串
*/
export const reFreshAccessToken = async (refreshToken: string) => {
let apiUrl = config.weChatApi002.replace('APPID', config.GZH.appId).replace('REFRESH_TOKEN', refreshToken);
let ret: any = await get(apiUrl);
if (!ret) {
throw userErrorHandler.find('errcode', 405);
}
if (ret.body) {
ret = ret.body.toString();
ret = JSON.parse(ret);
}
if (ret && (ret.errcode || !ret.access_token)) {
pLog.error(ret);
throw userErrorHandler.find('errcode', 401);
}
return ret;
};
在得到前端传过来的code之后, 按顺序调用let ret = getAccessToken (code)
,
再调用let userInfo = await getWeChatUserInfo(ret.access_token, ret.openid);
就得到用户信息了,把它存到数据库就算是用户登录了,生成一个token回去就ojbk了。
// ret的结构
let ret = { "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
// userInfo的结构
let userInfo = { "openid":" OPENID",
" nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}