獲取用戶手機號碼包含了”獲取用戶的昵稱、頭像授權”、”獲取用戶的手機號授權”和”解密手機號”3個部分。在小程序獲取了的手機號碼是加密的密文,還需要經過解密才能獲取明文手機號,解密的操作放在了服務器上。
1、獲取用戶的昵稱、頭像授權。
(1)小程序前端頁面代碼。
Open-type:微信開發能力,值為getUserInfo時獲取用戶信息,可以從bindgetuserinfo回調中獲取到用戶信息。
(2)彈出獲取昵稱、頭像授權窗口。
用戶點擊登錄,彈出微信授權窗口:
點擊允許,調用onGetUserInfo方法,獲取用戶信息:
// 通過按鈕讓微信用戶授權以獲取其信息
onGetUserInfo: function (e) {
var that = this;
wx.getUserInfo({
success(res) {
console.log(res);
if (res.errMsg == 'getUserInfo:ok') {
//將信息放入緩存
util.writeStorage(storage.WX_USER_Info, res.userInfo);
that.setData({
encrypted_UnionID: res.encryptedData,
iv_UnionID: res.iv
});
// that.obtainAuthorizationInformation();
that.setData({ showModal: true }); //顯示授權手機號彈窗
} else {
wx.showToast({
title: '授權用戶信息失敗,請重試',
icon: 'none'
})
}
// that.setData({
// encrypted_UnionID: res.encryptedData,
// iv_UnionID: res.iv
// });
},
fail(res) {
wx.showToast({
title: '獲取用戶基本信息失敗',
icon: 'none'
})
console.log('獲取用戶基本信息失敗!');
util.writeStorage(storage.AUTHORISED, 0);
}
});
}
2、獲取用戶手機號授權。
(1)獲取用戶信息之后,顯示准備獲取授權手機號彈窗 。
if (res.errMsg == 'getUserInfo:ok') {
//將信息放入緩存
util.writeStorage(storage.WX_USER_Info, res.userInfo);
that.setData({
encrypted_UnionID: res.encryptedData,
iv_UnionID: res.iv
});
// that.obtainAuthorizationInformation();
that.setData({ showModal: true }); //顯示授權手機號彈窗
}
(2)獲取手機號的前端頁面代碼。
<view class="toGetPhoneNumberShade" wx:if="{{ showModal }}" catchtap="closeModal"></view>
<view class="toGetPhoneNumber" wx:if="{{ showModal }}">
<view>
<image src="../../images/points.png"></image>
<text wx:if="{{ showShopName }}">商家名稱</text>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">微信用戶快捷登錄</button>
</view>
</view>
getPhoneNumber:
獲取用戶手機號,可以從bindgetphonenumber回調中獲取到用戶信息,具體說明 (小程序插件中不能使用)。
bindgetphonenumber: 獲取用戶手機號回調,open-type=getPhoneNumber時有效。
點擊”微信用戶快捷登錄”,彈出獲取手機號授權窗口:
(3)獲取手機號的js代碼
點擊允許,調用getPhoneNumber函數:
// 綁定手機號
getPhoneNumber: function (e) {
console.log("xxxxxxxxxxxxxxxx");
var that = this;
that.setData({ showModal: false }); //隱藏獲取手機號彈窗;
wx.checkSession({
success: function (res) { // session_key沒有過期
console.log(res);
var loginParams = {
'decryptSessionCode': that.data.decryptSessionCode, // 解密需要的參數
'encryptedUnionID': that.data.encrypted_UnionID, // 加密的unionID
'ivUnionID': that.data.iv_UnionID, // 解密需要的參數
'encryptedPhone': e.detail.encryptedData, // 加密的手機號
'ivPhone': e.detail.iv, // 解密需要的參數
'mobile': "",
'companySN': that.data.companySN
};
that.login(loginParams);
},
fail: function (res) { // session_key已過期,重新獲取
console.log(res);
wx.login({
success(res) {
that.setData({ decryptSessionCode: res.code });
},
fail(res) { // 這里需要處理調用接口失敗的情況
console.log('調用wx.login失敗');
}
});
wx.showToast({
title: '授權手機號失敗,請重試',
icon: 'none'
})
}
});
},
設置請求登錄變量loginParams,然后調用login函數。
(此時獲取的手機號還是加密的手機號encryptedPhone,解密的操作放在了服務器端,需要把decryptSessionCode、encryptedPhone、ivPhone幾個參數傳到服務器端。)
3、解密用戶的手機號。
解密手機號的操作在服務器端進行。
(1)請求服務器解密手機號碼的js代碼。
// 第一次登錄,非自動登錄
login: function (loginParams) {
// let header = wx.getStorageSync('storageHeader'); // TODO 需要處理nbr會話失效的情況
let that = this;
wx.showLoading({
title: '登錄中,請稍等',
mask: true
})
wx.request({
url: api.login,
method: api.POST,
header: app.globalData.header,
data: loginParams,
success(res) {
console.log(res);
console.log(res.data.objectList2);
util.writeStorage(storage.Company_Address, res.data.objectList2);
that.onRequestSuccess(res)
},
fail(res) { // 這里需要處理調用接口失敗的情況
console.log(res);
wx.hideLoading();
wx.showToast({
title: '登錄失敗,請重試',
icon: 'none'
})
return null;
}
});
},
(2)后端服務器解密手機號。
(2.1)向微信服務器獲取sessionKey。
根據SessionAndOpenid_URL、appid、secret、decryptSessionCode向微信服務器發送請求,獲取sessionKey(需要sessionKey才能解密手機號):
// 向微信請求sessionKey
String sessionAndOpenidURL = String.format(SessionAndOpenid_URL, MP_APPID, MP_SECRET, vip.getDecryptSessionCode());
JSONObject jsonObject = WxUtils.getDataFromWxServer(sessionAndOpenidURL);
if (jsonObject == null) {
logger.error("獲取openid和session_key失敗!!!");
params.put(JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
params.put(KEY_HTMLTable_Parameter_msg, "獲取微信session_key失敗!");
return false;
}
String sessionKey = jsonObject.getString("session_key"); // ...
if (StringUtils.isEmpty(sessionKey)) {
logger.error("獲取session_key失敗!");
params.put(KEY_HTMLTable_Parameter_msg, "獲取session_key失敗!");
params.put(JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
return false;
} else {
logger.debug("獲取的sessionKey:" + sessionKey);
}
getDataFromWxServer方法代碼:
/** 通用函數。 向微信服務器發送Get請求,返回JSON數據。 */
public static JSONObject getDataFromWxServer(String url) {
HttpClient httpClient = HttpClientBuilder.create().build();
try {
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);// 接收client執行的結果
HttpEntity entity = response.getEntity();
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");
return JSONObject.fromObject(result);
} else {
logger.error("向微信服務器發送Get請求發生錯誤!");
return null;
}
} catch (Exception e) {
logger.error("向微信服務器發送Get請求發生錯誤:" + e.getMessage());
return null;
}
}
(2.2)解密手機號。
根據sessionKey還有小程序傳過來的密文手機號encryptedPhone、ivPhone進行解密:
String mobile = decryptData(vip.getEncryptedPhone(), vip.getIvPhone(), sessionKey).getString("phoneNumber");
if (StringUtils.isEmpty(mobile) || mobile.length() != FieldFormat.LENGTH_Mobile) {
logger.error("解密手機號失敗!");
params.put(KEY_HTMLTable_Parameter_msg, "網絡異常,請稍后再試!");
params.put(JSON_ERROR_KEY, EnumErrorCode.EC_OtherError.toString());
return false;
}
這樣就可以得到明文的手機號碼 mobile 了。
decryptData方法代碼:
private JSONObject decryptData(String encryptedData, String ivData, String session_key) {
byte[] encrypted = Base64.decodeBase64(encryptedData);
byte[] iv = Base64.decodeBase64(ivData);
byte[] key = Base64.decodeBase64(session_key);
AESUtil aesUtil = new AESUtil(key, iv);
return JSONObject.fromObject(aesUtil.decrypt(encrypted));
}