oAuth2授权协议 & 微信授权登陆和绑定 & 多环境共用一个微信开发平台回调设置
OAuth2(open Auth)开放授权协议
授权码模式流程:
1、浏览器(客户端)点击一个比如使用微信登陆按钮
2、会跳到认证服务器页面,让用户选择是否授权
3、如果用户点击授权,那么会跳转到开始在链接上填写的回调地址 (redirect_uri),同时会产生一个授权码code
4、客户端又拿这个code去认证服务器请求access_token
5、有了access_token就可以去调用授权的接口,access_token有效期比较短,当access_token过期后可以refresh_token刷新access_token
微信登陆流程:
为了便于调试,可以在微信开发平台的回调上写本地服务比如egg启动的地址localhost:7001,只要和本地设置的回调地址同域名就可以生成二维码
1、引用http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
2、 实例化以下对象可以生成一个二维码
var obj = new WxLogin({
self_redirect:false, //是在iframe里跳转还是顶层窗口跳转
id:"login_container", //DOM容器放置二维码的区域
appid: "", //在应用开发平台申请
scope: "snsapi_login", //如果是网页应用填写这个
redirect_uri: "localhost:7001/reqAccessToken",//回调地址
state: "xxx",//附带传递的数据
style: "", //二维码行内样式
href: "" //外链样式
});
3、扫描这个二维码,会弹出授权页,点击授权会重定向到刚才的回调地址redirect_uri,并会自动附上code值,如果开始填了state值,这个时候也会返回刚才的state,可以用这个state的自定义值进行区分做登陆还是绑定
redirect_uri?code=CODE&state=STATE //点击授权的返回
redirect_uri?state=STATE //不授权的返回
4、然后在比如nodejs服务路由里拦截刚才的redirect_uri地址,然后获取这个code值,去调用获取access_token的接口
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
//appid和secret //开放平台提供的值,填上即可
//CODE 即上一步返回的code值
5、这个获取access_token的接口返回的数据
{
"access_token":"ACCESS_TOKEN", //调用进一步接口令牌
"expires_in":7200, //这个接口的过期时间
"refresh_token":"REFRESH_TOKEN",//刷新上面令牌的参数
"openid":"OPENID", //用户唯一标识
"scope":"SCOPE"
}
6、用openid和access_token获取用户基本信息
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
//上一步返回的openid和access_token
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" //用这个unionid进行绑定其他信息
}
7、拿unionid和用户填写的其他信息进行关联绑定,比如手机号,当用户下次绑定的时候,发现数据库里有了该手机号,则直接给用户跳转到扫码界面进行扫码登陆,如果当用户下次是直接扫码登陆,但是数据库里没有这个unionid,则给用户跳转到绑定界面让用户进行绑定
调试或多环境共用一个开发平台回调设置:
如果微信开发平台只注册了一个网站应用,只能填写一个回调地址,为了不影响本地开发调试,可以在服务端做一个转发:
比如回调地址是111.111.111.111:7001则给开发环境和生产环境加一个标识,当回调请求111.111.111.111:7001/env/dev/reqAccessToken 则重定向到 localhost:7001/reqAccessToken,如果111.111.111.111:7001/production/reqAccessToken则重定向到111.111.111.111:7001/reqAccessToken即可,本地生成二维码的redirect_uri就写111.111.111.111:7001/env/${env}即可,然后服务端路由拦截/env/:env,根据env做重定向判断。
//生成二维码的实例化对象redirect_uri填写
//跟微信开发平台填写的回调地址同域名
var redirectPrefix = "https://www.xxx.com";
var CURENV = '<%=env%>';
new WxLogin({
self_redirect: false,
id: "J_wechatCodeBind",
appid: "xxx",
scope: "snsapi_login",
redirect_uri: encodeURI(`${redirectPrefix}/env/${CURENV}`),
state:"",
style: "white",
href: ""
});
//路由拦截上面的回调GET请求
async redirectUrl() {
const ctx = this.ctx;
const curEnv = ctx.params.curEnv;
const code = ctx.query.code;
const state = ctx.query.state;
if (curEnv == 'dev') {
ctx.redirect(`http://localhost:7001/xxx/xxx/requestAccessToken?code=${code}&state=${state}`);
} else if (curEnv == 'test') {
ctx.redirect(`http://192.168.0.xxx:7006/xxx/xxx/requestAccessToken?code=${code}&state=${state}`);
} else {
ctx.redirect(`https://www.xxx.com/xxx/xxx/requestAccessToken?code=${code}&state=${state}`);
}
}