java實現(xiàn)微信小程序登錄態(tài)維護的示例代碼
相信不少喜歡開發(fā)的朋友都已經(jīng)知道微信小程序是個什么物種了,樓主也是從小程序內(nèi)測期間就開始關注,并且也寫過幾個已經(jīng)上線的微信小程序。但是基本上都是寫的純前端,最近樓主從后端到前端寫一個完整的小程序項目,中間碰到了一些問題,樓主會找一些個人覺得有學習價值的點不定時的拿出來跟大家分享,希望對你有一些幫助。
本次就從最基本的微信小程序登錄態(tài)維護開始吧。小程序官方api文檔里面有對登錄態(tài)的一個完整的解釋,并且有相關的代碼。想看詳情,可以出門右轉:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject 我第一次看的時候沒怎么看懂,并且代碼沒有提供java版本的,這讓一個java程序員情何以堪,所以在努力研究了以后決定要做一個java版本的簡單的demo放出來。
作為服務端,如果想獲得到使用微信小程序的會員信息,就需要小程序作為客戶端把會員的基本信息傳過來。類似于手機號,openId可以作為當前小程序中用戶的唯一性標志。然而如果把會員的openId信息明文直接在服務端與小程序端來回傳輸?shù)脑?,會有安全性的問題。萬一被別人得到這個openId,就相當于得到會員的手機號一樣,就可以做一些其他操作了,顯然是不安全的。
為了解決這一問題微信采用了相對安全的方式。
//app.js
App({
onLaunch: function() {
wx.login({
success: function(res) {
if (res.code) {
//發(fā)起網(wǎng)絡請求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('獲取用戶登錄態(tài)失敗!' + res.errMsg)
}
}
});
}
})
微信小程序端會調用wx.login的api,然后會得到一個code,這個code對外人來講是沒有任何意義的,可以放心的傳給服務端。服務端得到code以后,加上你申請小程序時的appId, app secret,去調微信的接口
就可以得到以下參數(shù):
- openid 用戶唯一標識
- session_key 會話密鑰
- unionid 本字段在滿足一定條件的情況下才返回
其中openid 就是會員的唯一性標記,此時服務端可以保存下來。
session_key 以后解密 unionId(整個開放平臺會員的唯一性標識)時有用。
服務端得到openid以后,為了后邊的交互,要保存下來。一般來講有兩種方式:一種是直接入數(shù)據(jù)庫,一種是采用效率高一點的緩存。樓主采用的是后者,方式是redis。
按照微信的建議此時需要生成一個不重復值作為openId的唯一性標識。這里采用的是java的uuid。然后把這個uuid值作為key,把openid以及后面會用到的session_key作為value,存進redis。并且把uuid值返回給小程序。這樣小程序就可以直接拿uuid值跟服務端交互。
也許會有人問,如果有人得到uuid值其實跟得到openid沒什么區(qū)別啊,都相當于是會員的唯一性標志。
所以這里要對這個uuid值進行一個處理。首先存入redis時要有時效性。session_key在微信服務器有效期是30天,建議服務端緩存session_key不超過30天。當小程序傳過來的uuid值過期時,認為這是過期的uuid,則重新走wx.login步驟。
為了方便redis中不僅會寸uuid與openid的對應關系。還會再存一條openid對應uuid的記錄,目的是為了下一次重新wx.login步驟時根據(jù)openid找到之前老的uuid,如果存在的話就刪掉,然后查詢一條新的uuid值,并且把openid對應的這條記錄也更新掉。這樣redis服務器中就不會有多余的臟數(shù)據(jù),減輕服務器的負擔。
以上就是我理解的整個登錄態(tài)的過程,當然還有wx.checkSession這些沒有講到,其實就是發(fā)現(xiàn)session_key失效是再重新走一遍上述的流程就可以了。所以沒有仔細說。不知道我有沒有講清楚。我會把整個流程的關鍵代碼貼出來,供大家參考。
@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("微信返回的結果 {}", ret);
if (ret == null || "".equals(ret)) {
logger.info("網(wǎng)絡超時");
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("微信返回的錯誤碼{}", errcode);
renderJson(new OutRoot().setCode("101").setMsg(SYS.CONTACT_FAIL));
} else if (obj.containsKey("session_key")) {
logger.info("調微信成功");
// 開始處理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值采用不會重復的uuid
String rsession = UUID.randomUUID().toString();
Cache tokenCache = Redis.use("redis_00");
// (3) 首先根據(jù)openId,取出來之前存的openId對應的sessionKey的值。
String oldSeesionKey = tokenCache.getJedis().get(openId);
if (oldSeesionKey != null && !"".equals(oldSeesionKey)) {
logger.info("oldSeesionKey==" + oldSeesionKey);
// (4) 刪除之前openId對應的緩存
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對應關系 : 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);
}
}
}
}
}
項目框架是我比較喜歡Jfinal,java輕量級急速開發(fā)框架,非常高效,也推薦給大家??赡苡心男┻z漏的地方歡迎大家積極提出意見和批評。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Java后端接入微信小程序登錄功能(登錄流程)
- java實現(xiàn)微信掃碼登錄第三方網(wǎng)站功能(原理和代碼)
- 微信小程序微信登錄的實現(xiàn)方法詳解(JAVA后臺)
- 詳解java實現(xiàn)簡單掃碼登錄功能(模仿微信網(wǎng)頁版掃碼)
- Java中基于Shiro,JWT實現(xiàn)微信小程序登錄完整例子及實現(xiàn)過程
- 使用weixin-java-tools完成微信授權登錄、微信支付的示例
- 第三方網(wǎng)站微信登錄java代碼實現(xiàn)
- java實現(xiàn) 微博登錄、微信登錄、qq登錄實現(xiàn)代碼
- Java實現(xiàn)微信登錄并獲取用戶信息功能(開發(fā)流程)
相關文章
使用java代碼實現(xiàn)保留小數(shù)點的位數(shù)
因為個人應用的需要,所以就寫個簡單點的了。希望大家都給給建議,共同學習。需要的朋友也可以參考下2013-07-07
Java Fluent Mybatis 項目工程化與常規(guī)操作詳解流程篇 下
Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強框架 fluent mybatis關于項目工程化與常規(guī)操作流程2021-10-10
Spring超詳細講解創(chuàng)建BeanDefinition流程
Spring在初始化過程中,將xml中定義的對象解析到了BeanDefinition對象中,我們有必要了解一下BeanDefinition的內(nèi)部結構,有助于我們理解Spring的初始化流程2022-06-06
java中獲取xml文件的某個配置節(jié)點內(nèi)容方式
這篇文章主要介紹了java中獲取xml文件的某個配置節(jié)點內(nèi)容方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
Java多線程程序中synchronized修飾方法的使用實例
synchronized關鍵字主要北用來進行線程同步,這里我們主要來演示Java多線程程序中synchronized修飾方法的使用實例,需要的朋友可以參考下:2016-06-06

