微信小程序的登陆
1、小程序获取openid, session_key
一、获取code,有效期五分钟,只能使用一次
二、使用code获取openid, session_key, [unionid]
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
console.log(res);
wx.request({
url: 'http://localhost/mpserver/login.php',
data: {
code: res.code
},
method: 'GET',
success: function(res) {
console.log(res.data)
}
})
}
})
<!-- 若是只是展现用户头像昵称,可使用 <open-data /> 组件 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
2、获取用户详细信息:受权
一、已受权过
已受权:wx.getUserInfo()
当用户未受权过,调用该接口将直接进入fail回调
当用户受权过,可使用该接口获取用户信息
如今的调用此接口没有弹框
app.js---------------------
onLoad: function() {
// 查看是否受权
wx.getSetting({
success: function(res){
if (res.authSetting['scope.userInfo']) {
// 已经受权,能够直接调用 getUserInfo 获取头像昵称,不会弹框,不是实时更新的,大概是两小时
wx.getUserInfo({
withCredentials: false,
success: function(res) {
// 能够将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo;
this.globalData.userInfo.openid = this.globalData.user.openid;
this.globalData.userInfo.session_key = this.globalData.user.session_key;
// 因为 getUserInfo 是网络请求,可能会在 Page.onLoad 以后才返回
// 因此此处加入 callback 以防止这种状况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
注:当 withCredentials 为 true 时,要求此前有调用过 wx.login 且登陆态还没有过时,此时返回的数据会包含 encryptedData, iv 等敏感信息;当 withCredentials 为 false 时,不要求有登陆态,返回的数据不包含 encryptedData, iv 等敏感信息。
二、未受权:要求以按钮的形式告知用户去点击来受权
<button wx:if="{{!hasUserInfo && canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
login.js---------------------
Page({
data: {
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: '../logs/logs'
})
},
onLoad: function () {
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse){
// 因为 getUserInfo 是网络请求,可能会在 Page.onLoad 以后才返回
// 因此此处加入 callback 以防止这种状况
app.userInfoReadyCallback = res => {
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
}
})
}
},
// 受权并返回用户信息
getUserInfo: function(e) {
console.log(e)
app.globalData.userInfo = e.detail.userInfo
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
})
}
})
返回:
userInfo OBJECT 用户信息对象,不包含 openid 等敏感信息
rawData String 不包括敏感信息的原始数据字符串,用于计算签名。
signature String 使用 sha1( rawData + sessionkey ) 获得字符串,用于校验用户信息,参考文档 signature。
encryptedData String 包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法
iv String 加密算法的初始向量,详细见加密数据解密算法
userInfo包含信息:
avatarUrl
city
country
gender
language
nickName
province
若是须要openid,unionid等信息,须要请求服务端解密encryptedData
getUserInfo: function(e) {
console.log(e);
var self = this;
wx.request({
url: 'http://localhost/mpserver/decrypt.php',
data: {
session_key: app.globalData.user.session_key,
encrypted_data: e.detail.encryptedData,
iv: e.detail.iv
},
method: 'POST',
header: {
'content-type': 'application/x-www-form-urlencoded'
},
success: function(res) {
console.log(res.data)
app.globalData.userInfo = res.data
self.setData({
userInfo: res.data,
hasUserInfo: true
})
}
})
}
服务端:
decrypt.php--------------------------------------------------------
<?php
date_default_timezone_set('Asia/Shanghai');
header('Content-Type:application/json; charset=utf-8');
require_once('lib/wxBizDataCrypt.php');
$appid = 'wx89137bb28d7cd3e6';
$sessionKey = $_POST['session_key'];
$encryptedData = $_POST['encrypted_data'];
$iv = $_POST['iv'];
$pc = new WXBizDataCrypt($appid, $sessionKey);
$errCode = $pc->decryptData($encryptedData, $iv, $data );
if ($errCode == 0) {
exit($data);
} else {
exit(json_encode(['status'=>false, 'errcode'=>$errCode]));
}
wxBizDataCrypt.php------------------------------------------------
<?php
/**
* 对微信小程序用户加密数据的解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
include_once "errorCode.php";
class WXBizDataCrypt
{
private $appid;
private $sessionKey;
/**
* 构造函数
* @param $sessionKey string 用户在小程序登陆后获取的会话密钥
* @param $appid string 小程序的appid
*/
public function __construct( $appid, $sessionKey)
{
$this->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;
}
}
errorCode.php-------------------------------------------------------
class ErrorCode
{
public static $OK = 0;
public static $IllegalAesKey = -41001;
public static $IllegalIv = -41002;
public static $IllegalBuffer = -41003;
public static $DecodeBase64Error = -41004;
}
解密后的信息:
{
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark":
{
"appid":"APPID",
"timestamp":TIMESTAMP
}
}
总结:
一、应用初始化 wx.login() ---> code ---> 服务端获得openid,session_key,unionid绑定到本系统的用户信息user ---> 将user返回给小程序(过滤掉openid,session_key,unionid参数) ---> 将userid做为小程序和服务端通信的标识。
二、若是已经受权过:wx.getUserInfo(),withCredentials: false,获取基本信息。
关于安全:
附加:
一、wx.request()方法说明,对于get,post方式有所不一样,默认请求方式get
data 数听说明:
最终发送给服务器的数据是 String 类型,若是传入的 data 不是 String 类型,会被转换成 String 。转换规则以下:
对于 GET 方法的数据,会将数据转换成 query string(encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)
对于 POST 方法且 header['content-type'] 为 application/json 的数据,会对数据进行 JSON 序列化,默认如此。
对于 POST 方法且 header['content-type'] 为 application/x-www-form-urlencoded 的数据,会将数据转换成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)...)
所以对于POST请求咱们应该设置
header: {
'content-type': 'application/x-www-form-urlencoded'
},
二、在wx.request()里面使用this表示该函数内部,若是想要设置值得话,须要换一个变量,在wx.request()外面 var self = this; 在wx.request()里面能够
self.globalData.user = res.data;来赋值,由于this是不存在globalData这个变量的,只有外部有这个变量。
三、关于session_key
开发者若是遇到由于session_key不正确而校验签名失败或解密失败,请关注下面几个与session_key有关的注意事项。
wx.login()调用时,用户的session_key会被更新而导致旧session_key失效。开发者应该在明确须要从新登陆时才调用wx.login(),及时经过登陆凭证校验接口更新服务器存储的session_key。
微信不会把session_key的有效期告知开发者。咱们会根据用户使用小程序的行为对session_key进行续期。用户越频繁使用小程序,session_key有效期越长。
开发者在session_key失效时,能够经过从新执行登陆流程获取有效的session_key。使用接口wx.checkSession()能够校验session_key是否有效,从而避免小程序反复执行登陆流程。
当开发者在实现自定义登陆态时,能够考虑以session_key有效期做为自身登陆态有效期,也能够实现自定义的时效性策略。
---------------------
原文:https://blog.csdn.net/raoxiaoya/article/details/97276131