小程序之合并网站与小程序的微信登录

背景:原先的网站用的微信登录是openid,随着小程序的火起,想拓展一个小程序论坛,但是用的是自己的openid,现在需要两边的用户合并起来;

需求:改进网站的微信登录和小程序的微信登录,使用微信用户的unionid来作为唯一标识,因为微信用户来说openid可以多个,unionid只有一个,所以就是获取unionid

思路简述:

网站的微信登录
  1. 准备一个二维码登录页和回调php文件,文档
  2. 用户扫码后获取临时code到回调方法,使用code+appid+appsecret发起请求
  3. 返回token和unionid,可以使用token获取用户信息
2.小程序的微信登录
  1. wx.login获取code发送给后端
  2. 后端请求接口获取session_key给小程序,小程序存session_key
  3. 小程序用getuserinfo返回加密数据+session_key给后端
  4. 后端用脚本解密获得用户敏感信息

简要代码解释:

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 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 2
hareluya

建议两个open_id都要存,不然之后支付或者发送模板信息就尴尬了。

5年前 评论
bestcyt

@hareluya 哎好的前辈以后会考虑的,主要这个是论坛小程序,所以没有支付这块啥的

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!