微信小程序的登錄
// 展示本地存儲能力
var logs = wx.getStorageSync('logs') || {};
logs.name = 'Tome';
logs.age = '28';
wx.setStorageSync('logs', logs);
一、小程序獲取openid, session_key
1、獲取code,有效期五分鍾,只能使用一次
2、使用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>
二、獲取用戶詳細信息:授權
1、已授權過
已授權: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 等敏感信息。
2、未授權:要求以按鈕的形式告知用戶去點擊來授權
<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
}
}
總結:
1、應用初始化 wx.login() ---> code ---> 服務端得到openid,session_key,unionid綁定到本系統的用戶信息user ---> 將user返回給小程序(過濾掉openid,session_key,unionid參數) ---> 將userid作為小程序和服務端通訊的標識。
2、如果已經授權過:wx.getUserInfo(),withCredentials: false,獲取基本信息。
關於安全:
附加:
1、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'
},
2、在wx.request()里面使用this表示該函數內部,如果想要設置值得話,需要換一個變量,在wx.request()外面 var self = this; 在wx.request()里面可以
self.globalData.user = res.data;來賦值,因為this是不存在globalData這個變量的,只有外部有這個變量。
3、關於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