花了好幾天時間,總算解決了微信小游戲的登錄。本來微信登錄就比較復雜,再加上前前后后改了些接口,更是痛苦。網上找到的資料總是些零零散散有新有舊,微信自己的文檔大致有一個流程,但一些要點和注意事項又語焉不詳。今天就從頭到尾整理一遍登錄過程吧,算是造福一下本就很苦鱉的程序猿,順便給自己也留個記錄。
首先介紹下這個流程的背景,這樣的話各位讀者就可以判斷,這對自己是不是有用了。當然,我相信在大多數情況下都是有用的。
一、這個流程是按照強聯網游戲來設計的,客戶端跟服務器通信用的是WebSocket,服務器端是Node.js。(如果你的服務器是PHP,那么流程可能更簡化一些)
二、玩家以純粹的新人身份進入游戲。(也就是,不假設玩家提前關注了相關公眾號之類的)
三、最終目的是獲取unionId。(如果你只想要openId,甚至連openId都不要,只要昵稱頭像,那可以更簡單。關於unionId和openId的區別,這里就不啰嗦了,相信大家都很清楚。)
登錄過程中比較麻煩的是用戶信息授權按鈕的處理,我沒有找到合適的辦法把它融合到流程中間,所以干脆就放最前面。在操作體驗上,就是玩家第一次進入游戲時,需要先點一個【微信登錄】的按鈕,授權游戲獲取用戶信息,然后再開始游戲。當然,以后再進游戲的話,因為已經授權過,所以就不會再有這個按鈕了。
那么下面就開始介紹流程了。
1、在客戶端,調用wx.getSetting檢查是否獲得授權。如果已經授權,進入下一步;否則,調用wx.createUserInfoButton顯示授權按鈕。
這一步通常會在游戲的登錄界面上,這個時候不會有【開始游戲】、【選擇服務器】之類的,而是一個【微信登錄】按鈕。點擊【微信登錄】,微信會提示用戶是否允許游戲訪問他的信息。允許之后,【微信登錄】消失,界面上會出現【開始游戲】或者【選擇服務器】的畫面。
如果用戶拒絕的話,最好也給一個彈窗,解釋為什么需要授權。
wx.getSetting({
success(res)
{
// 已授權
if (res.authSetting["scope.userInfo"])
{
// 進入下一步,比如【選擇服務器】
}
// 顯示授權按鈕
else
{
let sysInfo = wx.getSystemInfoSync();
let button = wx.createUserInfoButton({
type: "text",
text: "微信登錄",
style: {
left: sysInfo.windowWidth / 2 - 50,
top: sysInfo.windowHeight / 2 - 30,
width: 100,
height: 60,
backgroundColor: "#c7a976",
color: "#5c5941",
borderColor: "#5c5941",
textAlign: "center",
fontSize: 16,
borderWidth: 4,
borderRadius: 4,
lineHeight: 60,
}
});
button.onTap(function(res)
{
if (res.userInfo)
{
button.destroy();
// 進入下一步,比如【選擇服務器】
}
else
{
wx.showModal({
title: "溫馨提示",
content: "《XXX》是一款在線對戰游戲,需要您的用戶信息登錄游戲。",
showCancel: false,
});
}
});
button.show();
}
}
});
2、對於需要分區跨服的游戲,顯示【選擇服務器】的界面。
如果不需要分區,那么可以顯示一個【開始游戲】的界面(你也許覺得這一步可以省掉,但是為了結構清晰,我建議還是留着)。
這一步是游戲自己處理,跟微信無關,所以就沒代碼了。
3、連接游戲服務器;
在連接成功的回調里,調用wx.login,獲得code;
再調用wx.getUserInfo,獲得encryptedData和iv;
最后將code、encryptedData、iv發送給服務器。
因為用的是WebSocket,需要連接服務器的步驟,就在這里了。如果是PHP,可以省掉連接服務器,直接開始調用wx.login。
這一步獲得的參數很重要:code將被用來獲取sessionKey;而sessionKey、encryptedData、iv三者一起解出用戶的敏感數據(包括unionId等)。
// 連接游戲服務器成功的回調。如果服務器用的是PHP,這里直接調用wx.login
onConnected: function()
{
wx.login({
success: function(res)
{
// res中包含code
// 獲取用戶信息
wx.getUserInfo({
withCredentials: true, // 必須在wx.login之后,這里才能為true
success: function(result)
{
// result中包含encryptedData和iv
// 將res.code、result.encryptedData、result.iv發送到服務器
},
fail: function(result)
{
// 錯誤處理
},
});
},
fail: function(res)
{
// 錯誤處理
},
});
},
4、在服務器上收到數據后,首先調用微信的接口 https://api.weixin.qq.com/sns/jscode2session
這一步需要code,以及你的小游戲AppID和AppSecret,這兩個可以在微信公眾平台管理后台拿到。
值得一提的是,在微信后台上,AppSecret只能查看一次,然后你需要自己把它保存在某個隱秘的地方。如果你忘了保存,那么只能再重新生成一個AppSecret。
調用成功之后,可以拿到sessionKey。(同時還有openId)
然后,用sessionKey以及之前客戶端傳來的encryptedData、iv,解密得到unionId、openId、昵稱、頭像等等。有了這些數據,就可以開始游戲里的登錄了。
需要注意的是,小游戲要綁定了公眾號才有unionId。
// 服務器端的代碼
let https = require("https");
let iconv = require("iconv-lite");
// WXBizDataCrypt是微信提供的模塊,用來執行解密
// 可以在https://developers.weixin.qq.com/minigame/dev/tutorial/open-ability/signature.html找到下載鏈接
let WXBizDataCrypt = require("../lib/WXBizDataCrypt.js");
// WX_APP_ID是小游戲AppID,WX_APP_SECRET是小游戲AppSecret,code由客戶端發送上來
let url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + WX_APP_ID + "&secret=" + WX_APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
let req = https.get(url, function(res)
{
let datas = [];
let size = 0;
res.on("data", function(data)
{
datas.push(data);
size += data.length;
});
res.on("end", function()
{
let buff = Buffer.concat(datas, size);
let result = iconv.decode(buff, "utf8");
try
{
let d = JSON.parse(result);
if (d.session_key)
{
try
{
let wxCrypt = new WXBizDataCrypt(WX_APP_ID, d.session_key);
// encryptedData和iv都是客戶端傳遞的數據
let res = wxCrypt.decryptData(encryptedData, iv);
// res中包含了openId、unionId、nickName、avatarUrl等等信息
// 注意,如果你的小游戲沒有綁定微信公眾號,這里可能也不會有unionId
// 微信登錄完成,可以開始進入游戲了
}
catch (error)
{
// 錯誤處理
}
}
else
{
// 錯誤處理
}
}
catch (error)
{
// 錯誤處理
}
});
});
req.on("error", function(err)
{
// 錯誤處理
});
整個微信小游戲登錄過程,大致就是這樣了。最后順便提一下,調用https://api.weixin.qq.com/sns/jscode2session這一步,因為是https請求,所以你可能會覺得,也可以直接在客戶端調用。畢竟code就在客戶端,AppID和AppSecret也是固定的。但微信並不建議這么做(想想看,微信甚至不會替你保存AppSecret,你願意把它放客戶端里嗎?)
————————————————
原文鏈接:https://blog.csdn.net/SingleWizard/article/details/85252875