小程序授权登陆

所要实现效果如下图


登陆提示

授权

登陆成功

图二在手机端显示的效果其实是下面这样的


授权手机端

解决的问题其实是官方现在不可以使用wx.getUserInfo(OBJECT)来弹出授权窗口了,须使用button按钮来获取,文档说明在这。
如果要写个按钮给用户主动去点估计不大可能,所以采用组件来实现进入页面引导用户去点。官方有对组件的使用介绍:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/。


具体操作如下:
一、新建组件目录
在你想把组件内容放的位置文件夹右击-》新建Component,建议单独建一个文件夹。新建后开发者工具自动建立了js,wxss,json,wxml。我这里建立的四个文件命名为:dologin.js 、dologin.wxss、dologin.json、dologin.wxml
二、代码实现

dologin.js

// template/dologin.js
var util = require('../../utils/util.js');
var config = require('../../utils/config.js');
var app = getApp();
Component({
  options: {
    mutipleSlots: true
  },
  /**
   * 组件的属性列表
   */
  properties: {
    //弹窗标题
    title:{
      type: String,
      value: '标题' //默认值
    },
    //弹窗内容
    content: {
      type: String,
      value:'弹窗内容'
    },
    //弹窗确认按钮文字
    confirmText: {
      type: String,
      value: '确定'
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    //弹窗显示控制
    isShow:true
  },

  /**
   * 组件的方法列表
   */
  methods: {
    //隐藏弹窗
    hideDologin(){
      this.setData({
        isShow: false
      })
    },
    //展示弹窗
    showDologin(){
      this.setData({
        isShow: true
      })
    },
    /*
  *triggerEvent组件之间通信
  */
    confirmEvent() {
      this.triggerEvent("confirmEvent");
    },
    bindGetUserInfo(e) {
      this.triggerEvent("bindGetUserInfo",{event:e});
    }
  },
})

dologin.json

{
  "component": true,
  "usingComponents": {}
}

dologin.wxss

/* template/dologin.wxss */
.dialog-mask{
  position: fixed;
    z-index: 1000;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.3);
} .dialog-info{
    position: fixed;
    z-index: 5000;
    width: 80%;
    max-width: 600rpx;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
    background-color: #FFFFFF;
    text-align: center;
    border-radius: 3px;
    overflow: hidden;
} .dialog-title{
    font-size: 36rpx;
    padding: 30rpx 30rpx 10rpx;
} .dialog-content{
    padding: 10rpx 30rpx 20rpx;
    min-height: 80rpx;
    font-size: 32rpx;
    line-height: 1.3;
    word-wrap: break-word;
    word-break: break-all;
    color: #999999;
} .dialog-footer{
    display: flex;
    align-items: center;
    position: relative;
    line-height: 90rpx;
    font-size: 34rpx;
} .dialog-btn{
    display: block;
    -webkit-flex: 1;
    flex: 1;
    position: relative;
    color: #3CC51F;
}

dologin.wxml




然后在需要使用的地方进行如下代码操作:
我是在进入home就给出授权登陆的,所以

  • 我在home.json中首先引入组件
{
  "navigationBarTitleText": "首页",
  "enablePullDownRefresh": true,
  "backgroundTextStyle": "dark",
  "usingComponents":{
    "dialog": "../../template/dialog"
  }
}
  • 接着在home.wxml中写
 

  • 最后在home.js中的onReady函数中写
 //获得dialog组件
    this.dialog = this.selectComponent("#dialog");
  },
  showDologin: function () { 
    this.dialog.showDialog(); 
  }, 
  confirmEvent: function () { 
    this.dialog.hideDologin(); 
  }, 
  bindGetUserInfo: function (e) {
    // 用户点击授权后,这里可以做一些登陆操作 this.login();
    this.wxlogin(e.detail.event)
  },

代码分析
首先我们进入页面首页后,触发onReady函数对页面初次渲染,引入组件,显示弹窗,然后我们点击弹窗中的“”我知道了“”,这个按钮里绑定的是bindGetUserInfo授权参数,open-type="getUserInfo",事件是confirmEvent,点击后跳转到授权的选择,在组件的js文件中的组件交互里,使用triggerEvent来进行交互,作为登陆,需要传参,所以在后面可接入参数的传递{event:e}。最后在home.js中的bindGetUserInfo方法里进行登陆操作。


微信登陆

wxlogin: function (e) {
    if (e.detail.errMsg == 'getUserInfo:fail auth deny') {
      wx.showModal({
        title: '提示',
        content: '您已拒绝授权,请点击确定后换手机号码登录或者重新允许授权',
        success: function (res) { }
      })
      return false
    }
    wx.login({
      success: function (res) {  //使用encodeURI解决再次调用的时候解密失败错误-41003
        var code = encodeURI(res.code)
        var AppID = config.AppID
        var AppSecret = config.AppSecret
        var encrypted =encodeURI( e.detail.encryptedData)
        var iv = encodeURI(e.detail.iv)
        try {
          var cross_sn = wx.getStorageSync('cross_sn')
        } catch (e) {
          var cross_sn = ''
        }
        app.reqPost("login", "wxlogin", {
          code: code,
          encrypted: encrypted,
          iv: iv,
          appID: AppID,
          appSecret: AppSecret,
          cross_sn: cross_sn,
          cur_store: config.cur_store
        }, function (res) {
          wx.setStorageSync('token', res.data.datas.token)
          wx.setStorageSync('meReload', true)
          wx.setStorageSync('cartReload', true)
          wx.setStorageSync('goodsReload', true)
          wx.navigateBack()
        })
      }
    })
  },

后台代码

public function wxloginOp(){
        if($_REQUEST['platform']=='wxmini'){
            $json=$this->_getUserInfo();
        }
        else{
            $json=$this->get_access_tokenOp();
        }
        try{
            Model()->beginTransaction();
            $data=array();
            $data['openid']=empty($json->openid)?$json->openId:$json->openid;
            $data['nickname']=empty($json->nickname)?$json->nickName:$json->nickname;
            $data['headimgurl']=empty($json->avatarUrl)?$json->avatarUrl:$json->avatarurl;
            ···
            $data['unionid']=empty($json->unionid)?$json->unionId:$json->unionid;
            $data['add_time']=TIMESTAMP;
            $r=Model("wxlogin_userinfo")->addData($data);
            if(!$r)
                throw new Exception("网络繁忙");
            $model_member=Model("member");
            $unionId=empty($json->unionid)?$json->unionId:$json->unionid;
            $memberInfo=$model_member->getMemberInfo(array("unionid"=>$unionId));
            if(empty($memberInfo)){
                //此处业务代码省略
                $member_id=$model_member->addMember($memberInsert);
                if(!$member_id)
                    throw new Exception("网络繁忙");
                $memberInfo=$model_member->getMemberInfo(array("member_id"=>$member_id));
            }
            //此处业务代码省略
            if(empty($token)) {
                throw new Exception('网络繁忙');
            }
            Model()->commit();
            output_data(array("token"=>$token,"data"=>$data,"send_data"=>$send_data));
        }
        catch(Exception $e){
            Model()->rollback();
            output_error($e->getMessage());
        }
    }

private function _getUserInfo(){
        require_once(dirname(dirname(__FILE__)).DS."resource".DS.'wxBizDataCrypt.php');
        $code = $_REQUEST['code'];
        $appId = $_REQUEST['appID'];
        $appSecret = $_REQUEST['appSecret'];
        $grant_type="authorization_code";
        $url_get = 'https://api.weixin.qq.com/sns/jscode2session?appid='.$appId.'&secret='.$appSecret.'&js_code='.$code.'&grant_type='.$grant_type;
        try{
            $json=json_decode($this->curlGet($url_get));
            if (!$json->errmsg){
                $sessionKey = $json->session_key;
                $encryptedData=$_REQUEST['encrypted'];
                $iv=$_REQUEST['iv'];
                $appID=$_REQUEST['appID'];
                $pc = new WXBizDataCrypt($appID, $sessionKey);
                $errCode = $pc->decryptData($encryptedData, $iv, $data );
                if ($errCode == 0) {
                    return json_decode($data);
                } else {
                    throw new Exception($errCode);
                }
            }else {
                throw new Exception('获取session_key发生错误:错误代码'.$json->errcode.',微信返回错误信息:'.$json->errmsg);
            }
        }
        catch(Exception $e){
            output_error($e->getMessage());
        }
    }

private function curlGet($url,$method='get',$data=''){
        $ch = curl_init();
        $header=array();
        $header[] = "Accept-Charset: utf-8";
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $temp = curl_exec($ch);
        curl_close($ch);
        return $temp;
    }
sessionKey = $sessionKey;
        $this->appid = $appid;
    }


    /**
     * 检验数据的真实性,并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0,失败返回对应的错误码
     */
    public function decryptData( $encryptedData, $iv, &$data )
    {
        if (strlen($this->sessionKey) != 24) {
            return ErrorCode::$IllegalAesKey;
        }
        $aesKey=base64_decode($this->sessionKey);

        
        if (strlen($iv) != 24) {
            return ErrorCode::$IllegalIv;
        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);

        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

        $dataObj=json_decode( $result );
        if( $dataObj  == NULL )
        {
            return ErrorCode::$IllegalBuffer;
        }
        if( $dataObj->watermark->appid != $this->appid )
        {
            return ErrorCode::$IllegalBuffer;
        }
        $data = $result;
        return ErrorCode::$OK;
    }

}

至此,实现完成。在开发者工具中测试的时候,每测试一次需要清理缓存。下一篇总结小程序消息推送功能的实现。

//使用encodeURI解决再次调用的时候解密失败错误-41003
在小程序前端:
var code = encodeURI(res.code)
var AppID = config.AppID
var AppSecret = config.AppSecret
var encrypted =encodeURI( e.detail.encryptedData)
var iv = encodeURI(e.detail.iv)
更新:2019-5-7

参考链接:
https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/
https://blog.csdn.net/YZ0826/article/details/80371132#commentsedit
https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html

你可能感兴趣的:(小程序授权登陆)