java實現微信小程序登錄态維護
發表時(shí)間:2021-4-12
發布人(rén):融晨科技
浏覽次數:68
相信不(bù)少喜歡開發的(de)朋友都已經知道(dào)微信小程序是(shì)個(gè)什麽物種了(le/liǎo),樓主也(yě)是(shì)從小程序内測期間就(jiù)開始關注,并且也(yě)寫過幾個(gè)已經上(shàng)線的(de)微信小程序。但是(shì)基本上(shàng)都是(shì)寫的(de)純前端,最近樓主從後端到(dào)前端寫一個(gè)完整的(de)小程序項目,中間碰到(dào)了(le/liǎo)一些問題,樓主會找一些個(gè)人(rén)覺得有學習價值的(de)點不(bù)定時(shí)的(de)拿出(chū)來(lái)跟大(dà)家分享,希望對你有一些幫助。
????本次就(jiù)從最基本的(de)微信小程序登錄态維護開始吧。小程序官方api文檔裏面有對登錄态的(de)一個(gè)完整的(de)解釋,并且有相關的(de)代碼。想看詳情,可以(yǐ)出(chū)門右轉:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject我第一次看的(de)時(shí)候沒怎麽看懂,并且代碼沒有提供java版本的(de),這(zhè)讓一個(gè)java程序員情何以(yǐ)堪,所以(yǐ)在(zài)努力研究了(le/liǎo)以(yǐ)後決定要(yào / yāo)做一個(gè)java版本的(de)簡單的(de)demo放出(chū)來(lái)。
????作爲(wéi / wèi)服務端,如果想獲得到(dào)使用微信小程序的(de)會員信息,就(jiù)需要(yào / yāo)小程序作爲(wéi / wèi)客戶端把會員的(de)基本信息傳過來(lái)。類似于(yú)手機号,openId可以(yǐ)作爲(wéi / wèi)當前小程序中用戶的(de)唯一性标志。然而(ér)如果把會員的(de)openId信息明文直接在(zài)服務端與小程序端來(lái)回傳輸的(de)話,會有安全性的(de)問題。萬一被别人(rén)得到(dào)這(zhè)個(gè)openId,就(jiù)相當于(yú)得到(dào)會員的(de)手機号一樣,就(jiù)可以(yǐ)做一些其他(tā)操作了(le/liǎo),顯然是(shì)不(bù)安全的(de)。
????爲(wéi / wèi)了(le/liǎo)解決這(zhè)一問題微信采用了(le/liǎo)相對安全的(de)方式。
//app.js
App({
onLaunch: function() {
wx.login({
success: function(res) {
if (res.code) {
//發起網絡請求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('獲取用戶登錄态失敗!' + res.errMsg)
}
}
});
}
})
微信小程序端會調用wx.login的(de)api,然後會得到(dào)一個(gè)code,這(zhè)個(gè)code對外人(rén)來(lái)講是(shì)沒有任何意義的(de),可以(yǐ)放心的(de)傳給服務端。服務端得到(dào)code以(yǐ)後,加上(shàng)你申請小程序時(shí)的(de)appId, app secret,去調微信的(de)接口
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
就(jiù)可以(yǐ)得到(dào)以(yǐ)下參數:
openid 用戶唯一标識
session_key 會話密鑰
unionid 本字段在(zài)滿足一定條件的(de)情況下才返回
其中openid 就(jiù)是(shì)會員的(de)唯一性标記,此時(shí)服務端可以(yǐ)保存下來(lái)。
session_key 以(yǐ)後解密 unionId(整個(gè)開放平台會員的(de)唯一性标識)時(shí)有用。
????服務端得到(dào)openid以(yǐ)後,爲(wéi / wèi)了(le/liǎo)後邊的(de)交互,要(yào / yāo)保存下來(lái)。一般來(lái)講有兩種方式:一種是(shì)直接入數據庫,一種是(shì)采用效率高一點的(de)緩存。樓主采用的(de)是(shì)後者,方式是(shì)redis。
????按照微信的(de)建議此時(shí)需要(yào / yāo)生成一個(gè)不(bù)重複值作爲(wéi / wèi)openId的(de)唯一性标識。這(zhè)裏采用的(de)是(shì)java的(de)uuid。然後把這(zhè)個(gè)uuid值作爲(wéi / wèi)key,把openid以(yǐ)及後面會用到(dào)的(de)session_key作爲(wéi / wèi)value,存進redis。并且把uuid值返回給小程序。這(zhè)樣小程序就(jiù)可以(yǐ)直接拿uuid值跟服務端交互。
????也(yě)許會有人(rén)問,如果有人(rén)得到(dào)uuid值其實跟得到(dào)openid沒什麽區别啊,都相當于(yú)是(shì)會員的(de)唯一性标志。
????所以(yǐ)這(zhè)裏要(yào / yāo)對這(zhè)個(gè)uuid值進行一個(gè)處理。首先存入redis時(shí)要(yào / yāo)有時(shí)效性。session_key在(zài)微信服務器有效期是(shì)30天,建議服務端緩存session_key不(bù)超過30天。當小程序傳過來(lái)的(de)uuid值過期時(shí),認爲(wéi / wèi)這(zhè)是(shì)過期的(de)uuid,則重新走wx.login步驟。
????爲(wéi / wèi)了(le/liǎo)方便redis中不(bù)僅會寸uuid與openid的(de)對應關系。還會再存一條openid對應uuid的(de)記錄,目的(de)是(shì)爲(wéi / wèi)了(le/liǎo)下一次重新wx.login步驟時(shí)根據openid找到(dào)之(zhī)前老的(de)uuid,如果存在(zài)的(de)話就(jiù)删掉,然後查詢一條新的(de)uuid值,并且把openid對應的(de)這(zhè)條記錄也(yě)更新掉。這(zhè)樣redis服務器中就(jiù)不(bù)會有多餘的(de)髒數據,減輕服務器的(de)負擔。
????以(yǐ)上(shàng)就(jiù)是(shì)我理解的(de)整個(gè)登錄态的(de)過程,當然還有wx.checkSession這(zhè)些沒有講到(dào),其實就(jiù)是(shì)發現session_key失效是(shì)再重新走一遍上(shàng)述的(de)流程就(jiù)可以(yǐ)了(le/liǎo)。所以(yǐ)沒有仔細說(shuō)。不(bù)知道(dào)我有沒有講清楚。我會把整個(gè)流程的(de)關鍵代碼貼出(chū)來(lái),供大(dà)家參考。
@ActionKey("/loginByWeixin")
public void loginByWeixin() throws Exception {
logger.info("Start getSessionKey");
String json = HttpKit.readData(getRequest());
JSONObject reqJson = JSON.parseObject(json);
String jsCode = reqJson.getString("code");
if (jsCode == null || "".equals(jsCode)) {
logger.info("缺少必要(yào / yāo)參數");
renderJson(new OutRoot().setCode("100").setMsg(SYS.PARAMETER_FAIL));
} else {
List<Record> record = appInfoService.selectAppInfo();
String appId = record.get(0).get("app_id");
String appSecret = record.get(0).getStr("app_secret");
if (appId == null || "".equals(appId) || appSecret == null || "".equals(appSecret)) {
logger.info("缺少必要(yào / yāo)參數");
renderJson(new OutRoot().setCode("100").setMsg(SYS.PARAMETER_FAIL));
} else {
String url = "https://api.weixin.qq.com/sns/jscode2session";
String httpUrl = url + "?appid=" + appId + "&secret=" + appSecret + "&js_code=" + jsCode
+ "&grant_type=authorization_code";
String ret =