所要实现效果如下图
图二在手机端显示的效果其实是下面这样的
解决的问题其实是官方现在不可以使用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
{{ title }}
{{ content }}
然后在需要使用的地方进行如下代码操作:
我是在进入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