java實(shí)現(xiàn)微信小程序登錄態(tài)維護(hù)的示例代碼
相信不少喜歡開發(fā)的朋友都已經(jīng)知道微信小程序是個(gè)什么物種了,樓主也是從小程序內(nèi)測(cè)期間就開始關(guān)注,并且也寫過幾個(gè)已經(jīng)上線的微信小程序。但是基本上都是寫的純前端,最近樓主從后端到前端寫一個(gè)完整的小程序項(xiàng)目,中間碰到了一些問題,樓主會(huì)找一些個(gè)人覺得有學(xué)習(xí)價(jià)值的點(diǎn)不定時(shí)的拿出來跟大家分享,希望對(duì)你有一些幫助。
本次就從最基本的微信小程序登錄態(tài)維護(hù)開始吧。小程序官方api文檔里面有對(duì)登錄態(tài)的一個(gè)完整的解釋,并且有相關(guān)的代碼。想看詳情,可以出門右轉(zhuǎn):https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject 我第一次看的時(shí)候沒怎么看懂,并且代碼沒有提供java版本的,這讓一個(gè)java程序員情何以堪,所以在努力研究了以后決定要做一個(gè)java版本的簡(jiǎn)單的demo放出來。
作為服務(wù)端,如果想獲得到使用微信小程序的會(huì)員信息,就需要小程序作為客戶端把會(huì)員的基本信息傳過來。類似于手機(jī)號(hào),openId可以作為當(dāng)前小程序中用戶的唯一性標(biāo)志。然而如果把會(huì)員的openId信息明文直接在服務(wù)端與小程序端來回傳輸?shù)脑?,?huì)有安全性的問題。萬一被別人得到這個(gè)openId,就相當(dāng)于得到會(huì)員的手機(jī)號(hào)一樣,就可以做一些其他操作了,顯然是不安全的。
為了解決這一問題微信采用了相對(duì)安全的方式。
//app.js App({ onLaunch: function() { wx.login({ success: function(res) { if (res.code) { //發(fā)起網(wǎng)絡(luò)請(qǐng)求 wx.request({ url: 'https://test.com/onLogin', data: { code: res.code } }) } else { console.log('獲取用戶登錄態(tài)失??!' + res.errMsg) } } }); } })
微信小程序端會(huì)調(diào)用wx.login的api,然后會(huì)得到一個(gè)code,這個(gè)code對(duì)外人來講是沒有任何意義的,可以放心的傳給服務(wù)端。服務(wù)端得到code以后,加上你申請(qǐng)小程序時(shí)的appId, app secret,去調(diào)微信的接口
就可以得到以下參數(shù):
- openid 用戶唯一標(biāo)識(shí)
- session_key 會(huì)話密鑰
- unionid 本字段在滿足一定條件的情況下才返回
其中openid 就是會(huì)員的唯一性標(biāo)記,此時(shí)服務(wù)端可以保存下來。
session_key 以后解密 unionId(整個(gè)開放平臺(tái)會(huì)員的唯一性標(biāo)識(shí))時(shí)有用。
服務(wù)端得到openid以后,為了后邊的交互,要保存下來。一般來講有兩種方式:一種是直接入數(shù)據(jù)庫,一種是采用效率高一點(diǎn)的緩存。樓主采用的是后者,方式是redis。
按照微信的建議此時(shí)需要生成一個(gè)不重復(fù)值作為openId的唯一性標(biāo)識(shí)。這里采用的是java的uuid。然后把這個(gè)uuid值作為key,把openid以及后面會(huì)用到的session_key作為value,存進(jìn)redis。并且把uuid值返回給小程序。這樣小程序就可以直接拿uuid值跟服務(wù)端交互。
也許會(huì)有人問,如果有人得到uuid值其實(shí)跟得到openid沒什么區(qū)別啊,都相當(dāng)于是會(huì)員的唯一性標(biāo)志。
所以這里要對(duì)這個(gè)uuid值進(jìn)行一個(gè)處理。首先存入redis時(shí)要有時(shí)效性。session_key在微信服務(wù)器有效期是30天,建議服務(wù)端緩存session_key不超過30天。當(dāng)小程序傳過來的uuid值過期時(shí),認(rèn)為這是過期的uuid,則重新走wx.login步驟。
為了方便redis中不僅會(huì)寸uuid與openid的對(duì)應(yīng)關(guān)系。還會(huì)再存一條openid對(duì)應(yīng)uuid的記錄,目的是為了下一次重新wx.login步驟時(shí)根據(jù)openid找到之前老的uuid,如果存在的話就刪掉,然后查詢一條新的uuid值,并且把openid對(duì)應(yīng)的這條記錄也更新掉。這樣redis服務(wù)器中就不會(huì)有多余的臟數(shù)據(jù),減輕服務(wù)器的負(fù)擔(dān)。
以上就是我理解的整個(gè)登錄態(tài)的過程,當(dāng)然還有wx.checkSession這些沒有講到,其實(shí)就是發(fā)現(xiàn)session_key失效是再重新走一遍上述的流程就可以了。所以沒有仔細(xì)說。不知道我有沒有講清楚。我會(huì)把整個(gè)流程的關(guān)鍵代碼貼出來,供大家參考。
@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("缺少必要參數(shù)"); 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("缺少必要參數(shù)"); 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 = HttpRequest.sendGetRequest(httpUrl); logger.info("微信返回的結(jié)果 {}", ret); if (ret == null || "".equals(ret)) { logger.info("網(wǎng)絡(luò)超時(shí)"); renderJson(new OutRoot().setCode("101").setMsg(SYS.CONTACT_FAIL)); } else { JSONObject obj = JSONObject.parseObject(ret); if (obj.containsKey("errcode")) { String errcode = obj.get("errcode").toString(); logger.info("微信返回的錯(cuò)誤碼{}", errcode); renderJson(new OutRoot().setCode("101").setMsg(SYS.CONTACT_FAIL)); } else if (obj.containsKey("session_key")) { logger.info("調(diào)微信成功"); // 開始處理userInfo String openId = obj.get("openid").toString(); Record tbMember = new Record(); tbMember.set("weixin_openid", openId); System.out.println("openId==" + openId); // 先查詢openId存在不存在,存在不入庫,不存在就入庫 List<Record> memberList = tbMemberService.selectMember(tbMember); if (memberList != null && memberList.size() > 0) { logger.info("openId已經(jīng)存在,不需要插入"); } else { JSONObject rawDataJson = reqJson.getJSONObject("userInfo"); String nickName = rawDataJson.getString("nickName"); String avatarUrl = rawDataJson.getString("avatarUrl"); String gender = rawDataJson.getString("gender"); String province = rawDataJson.getString("province"); String city = rawDataJson.getString("city"); String country = rawDataJson.getString("country"); tbMember.set("gender", gender); tbMember.set("nick_name", nickName); tbMember.set("avatar_url", avatarUrl); Long openId2 = tbMemberService.addMember(tbMember); logger.info("openId不存在,插入數(shù)據(jù)庫"); } // (1) 獲得sessionkey String sessionKey = obj.get("session_key").toString(); logger.info("sessionKey==" + sessionKey); logger.info("openId==" + openId); // (2) 得到sessionkey以后存到緩存,key值采用不會(huì)重復(fù)的uuid String rsession = UUID.randomUUID().toString(); Cache tokenCache = Redis.use("redis_00"); // (3) 首先根據(jù)openId,取出來之前存的openId對(duì)應(yīng)的sessionKey的值。 String oldSeesionKey = tokenCache.getJedis().get(openId); if (oldSeesionKey != null && !"".equals(oldSeesionKey)) { logger.info("oldSeesionKey==" + oldSeesionKey); // (4) 刪除之前openId對(duì)應(yīng)的緩存 tokenCache.getJedis().del(oldSeesionKey); logger.info("老的openId刪除以后==" + tokenCache.getJedis().get(oldSeesionKey)); } // (5) 開始緩存新的sessionKey: key --> uuid, value --> sessionObj JSONObject sessionObj = new JSONObject(); sessionObj.put("openId", openId); sessionObj.put("sessionKey", sessionKey); tokenCache.getJedis().set(rsession, sessionObj.toJSONString()); // (6) 開始緩存新的openId與session對(duì)應(yīng)關(guān)系 : key --> openId , value --> rsession tokenCache.getJedis().set(openId, rsession); String newOpenId = tokenCache.getJedis().get(openId); String newrSession = tokenCache.getJedis().get(rsession); logger.info("新的openId==" + newOpenId); logger.info("新的newrSession==" + newrSession); // (7) 把新的sessionKey返回給小程序 JSONObject objret = new JSONObject(); objret.put("rdSessionKey", rsession); objret.put("errno", 0); renderJson(objret); } } } } }
項(xiàng)目框架是我比較喜歡Jfinal,java輕量級(jí)急速開發(fā)框架,非常高效,也推薦給大家??赡苡心男┻z漏的地方歡迎大家積極提出意見和批評(píng)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java后端接入微信小程序登錄功能(登錄流程)
- java實(shí)現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)
- 微信小程序微信登錄的實(shí)現(xiàn)方法詳解(JAVA后臺(tái))
- 詳解java實(shí)現(xiàn)簡(jiǎn)單掃碼登錄功能(模仿微信網(wǎng)頁版掃碼)
- Java中基于Shiro,JWT實(shí)現(xiàn)微信小程序登錄完整例子及實(shí)現(xiàn)過程
- 使用weixin-java-tools完成微信授權(quán)登錄、微信支付的示例
- 第三方網(wǎng)站微信登錄java代碼實(shí)現(xiàn)
- java實(shí)現(xiàn) 微博登錄、微信登錄、qq登錄實(shí)現(xiàn)代碼
- Java實(shí)現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程)
相關(guān)文章
Java實(shí)現(xiàn)每日給女友微信發(fā)送早安信息
這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)每日給女友微信發(fā)送早安等微信信息,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下2022-12-12如何使用Spring Cloud Feign日志查看請(qǐng)求響應(yīng)
這篇文章主要介紹了如何使用Spring Cloud Feign日志查看請(qǐng)求響應(yīng),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02透徹理解Java中Synchronized(對(duì)象鎖)和Static Synchronized(類鎖)的區(qū)別
這篇文章主要介紹了Java中Synchronized(對(duì)象鎖)和Static Synchronized(類鎖)的區(qū)別,希望對(duì)大家有所幫助,一起跟隨小編過來看看吧2018-05-05Spring內(nèi)存緩存Caffeine的基本使用教程分享
Caffeine作為當(dāng)下本地緩存的王者被大量的應(yīng)用再實(shí)際的項(xiàng)目中,可以有效的提高服務(wù)吞吐率、qps,降低rt,本文就來簡(jiǎn)單介紹下Caffeine的使用姿勢(shì)吧2023-03-03Java生成隨機(jī)姓名、性別和年齡的實(shí)現(xiàn)示例
這篇文章主要介紹了Java生成隨機(jī)姓名、性別和年齡的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09使用hutool工具進(jìn)行導(dǎo)入導(dǎo)出excel表格
如何在后臺(tái)添加導(dǎo)入導(dǎo)出表格的功能呢,本期的文章將會(huì)帶領(lǐng)小伙伴們一起實(shí)現(xiàn)此功能,文中有詳細(xì)的代碼示例和圖文介紹,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-10-10SpringBoot優(yōu)化啟動(dòng)速度的方法實(shí)現(xiàn)
本篇文章主要介紹了SpringBoot優(yōu)化啟動(dòng)速度的方法實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01mybatis plus表的創(chuàng)建時(shí)間和修改時(shí)間的操作方法
這篇文章主要介紹了mybatis plus表的創(chuàng)建時(shí)間和修改時(shí)間的實(shí)現(xiàn)方法,本文給大家分享兩種方法,每種方法通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09