小程序之合并网站与小程序的微信登录
背景:原先的网站用的微信登录是openid,随着小程序的火起,想拓展一个小程序论坛,但是用的是自己的openid,现在需要两边的用户合并起来;
需求:改进网站的微信登录和小程序的微信登录,使用微信用户的unionid来作为唯一标识,因为微信用户来说openid可以多个,unionid只有一个,所以就是获取unionid
思路简述:
网站的微信登录
- 准备一个二维码登录页和回调php文件,文档
- 用户扫码后获取临时code到回调方法,使用code+appid+appsecret发起请求
- 返回token和unionid,可以使用token获取用户信息
2.小程序的微信登录
- wx.login获取code发送给后端
- 后端请求接口获取session_key给小程序,小程序存session_key
- 小程序用getuserinfo返回加密数据+session_key给后端
- 后端用脚本解密获得用户敏感信息
简要代码解释:
1.网站登录
扫码页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"> //嵌入js,详细可以看文档
</head>
<body>
<iframe style="width: 500px;height: 500px" src="https://open.weixin.qq.com/connect/qrconnect?appid=appod&redirect_uri=https://www.demo.info%2fminapp%2f2.0%2findex.php%3fmod%3dpass&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect" id="login_container"></iframe>
<script>
var obj = new WxLogin({
self_redirect:false,
id:"login_container",
appid: "xxxx",
scope: "snsapi_login",
redirect_uri: "https://www.demo.info/minapp/2.0/index.php?mod=pass",
state: "",
style: "",
href: ""
});
</script>
</body>
</html>
回调方法
$appId = 'xxx';
$appSecret = 'xxxx';
$code = $_GET['code'];
$getAccessTokenUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token?'
.'appid='.$appId
.'&secret='.$appSecret
.'&code='.$code
.'&grant_type=authorization_code';
$getAccessTokenResult = json_decode(getCurl($getAccessTokenUrl),true);
/*返回token和expires_in,refresh_token,openid,scope,unionid
* $getAccessTokenResult
* {
"access_token": "13_6soYEfSavs15T3WNaQg7OY1T4Jo7DUdwk5uGIO2sTEhSVHIxgqaXBq96D-LeXMiwVKmBlG36RYb6tWGNX0UCKw",
"expires_in": 7200,
"refresh_token": "13_sj9S_-ZF_mdTabZB2kYXuD1TCwrxybugHETkNihDKAXg8dcjEaghOsnlkIOO7GZT-OID0TWXDM1gJoqv8YO5NQ",
"openid": "oEPtT0W7GN7uGg4aYV1sLJFFd_iE",
"scope": "snsapi_login",
"unionid": "ccccccccccccccccccccccc"
}
*/
//1.获取到unionid
$accessToken = $getAccessTokenResult['access_token'];
$refreshToken = $getAccessTokenResult['refresh_token'];
$unionId = $getAccessTokenResult['unionid'];
然后看到是否有该unionid的用户,没有就创建新用户
重定向走
2.小程序登录
1. wx.login获取code发送给后端
wx.login({
success: function (res) {
//微信js_code
that.setData({
wxcode: res.code
}),
that.GetSessionTest();
}
})
2. 后端请求接口获取openid和session_key给小程序,小程序存session_key
GetSessionTest: function () {
var that = this;
wx.request({
url: that.data.HostUrl + "mod=wxlogin&login_test=1&getSession=1",
method: 'POST',
data: {
'code': that.data.wxcode,
'username': that.data.userName
},
header: {
'Content-Type': 'application/json'
},
success: function (res) {
console.log('保存返回的sessionkey:' + res.data.session_key);
wx.setStorageSync('session_key', res.data.session_key)
//获取用户信息
wx.getUserInfo({
withCredentials: true,
success: function (res) {
//获取用户敏感数据密文和偏移向量
that.setData({
userName: res.userInfo.nickName,
})
var encryptedData = res.encryptedData;
var iv = res.iv;
//返回加密数据,带入getSession,获取unionId
that.GetIvDataTest(iv, encryptedData);
}
})
}
})
},
3. 小程序用getuserinfo返回明个数据+session_key给后端
GetIvDataTest: function (iv, encryptedData) {
var that = this;
var session_key = '';
//同步获取session_key
try {
session_key = wx.getStorageSync('session_key')
if (session_key) {
// Do something with return value
console.log('查看sessionkey:' + session_key);
wx.request({
url: that.data.HostUrl + "mod=wxlogin&login_test=1&getInfo=1",
method: 'POST',
data: {
'iv': iv,
'encryptedData': encryptedData,
'session_key': session_key
},
header: {
'Content-Type': 'application/json'
},
success: function (res) {
if (res.data.errcode == 0) {
if (res.data.isbind == 1) {
utils.showSuccess('登录成功');
wx.setStorage({
key: "userInfo",
data: res.data
})
wx.switchTab({
url: '../../pages/setting/setting'
})
} else {
wx.hideToast();
wx.showModal({
title: '提示',
content: '是否绑定已有账号?',
cancelText: '跳过',
success: function (res2) {
if (res2.confirm) {
wx.redirectTo({
url: '../../pages/bind/bind?openid=' + res.data.openid,
})
} else if (res2.cancel) {
that.BindReg(res.data.openid, res.data.new_username)
}
}
})
}
} else {
utils.showModel('提示', res.data.errmsg)
}
}
})
}
} catch (e) {
console.log('获取sessionkey失败');
// Do something when catch error
}
},
4. 后端用脚本解密获得用户敏感信息,解密脚本文件可在官网的demo下载
$appid = 'xxx';
$appsecret = 'ccc';
$postval = file_get_contents('php://input');
$postData = json_decode($postval,true);
if($_GET['getSession']){
//1.根据code获取sessionkey,保存到session
//wx.login 获取到session_key
$url = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$appid.'&secret='.$appsecret.'&js_code='.$postData['code'].'&grant_type=authorization_code';
$wx_result = curl_get($url);
$wx_result = json_decode($wx_result,true);
$user_sussion_key = $wx_result['session_key'];
$user_openid = $wx_result['openid'];
$_SESSION['session_key'] = $user_sussion_key;
odz_result($wx_result);
}
if($_GET['getInfo']){
//2.根据wx.getUserInfo api 获取加密数据,再用session中的key来解密
//获取post的encryptedData和iv还有signature等可以做验证
$encryptedData = $postData['encryptedData'];
$iv = $postData['iv'];
$pc = new WXBizDataCrypt($appid, $postData['session_key']);
$errCode = $pc->decryptData($encryptedData, $iv, $data );
//获取加密数据 - 》 解密后即可得到unionid
// odz_result(array(
// 'data'=>$data,
// 'encryptedData'=>$encryptedData,
// 'iv'=>$iv,
// 'session_key'=>$postData['session_key'],
// 'odz_result'=>'odz_result'
// ));
//去除data中的用户信息 unionid,然后查找表中是否有这个unionid记录 , 看是否有绑定
//使用unionid代替openid
$wx_result = json_decode($data,true);
$unionId = $data['unionId'];
然后判断该用户是否绑定,否就创建新用户
记录事项
1.网站登录的access_token是网页授权token,这个是针对每个用户的获取信息
2.小程序要获取unionid是需要保存sessionkey这个东西
有错误或者不足之处请不吝赐教,坚持开源坚持分享 : )
本作品采用《CC 协议》,转载必须注明作者和本文链接
建议两个open_id都要存,不然之后支付或者发送模板信息就尴尬了。
@hareluya 哎好的前辈以后会考虑的,主要这个是论坛小程序,所以没有支付这块啥的