<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
微信小程式
開發平臺,提供有一類 API
,可以讓開發者獲取到微信登入使用者的個人資料。這類 API
統稱為開放介面
。
Tip:微信小程式開發平臺,會把微信登入使用者的個人資訊分為明文資料和敏感資料。
明文資料也稱為公開資料,開發者可以直接獲取到,如登入者的暱稱、頭像……
敏感資料如電話號碼、唯一識別符號……等資料,只有高階認證開發者和經過登入者授權後才能解密獲取到。
這一類 API
較多,且 API
之間功能有重疊之處,相互之間的區別較微小。有的適用於低版本,有的適用於高版本。
為了避免在使用時出現選擇混亂,本文將通過具體應用案例介紹幾個常用 API
的使用。
開放介面
是對一類 API
的統稱,開發者
可以通過呼叫這類介面得到微信登入使用者的授權
或獲取登入者的個人資料
。開放介面
又分成幾個子類 API
:
wx.pluginLogin(Object args)
、wx.login(Object object)
、wx.checkSession(Object object)
幾 個 API
。Object wx.getAccountInfoSync()
此介面用來獲取開發者的賬號資訊。wx.getUserProfile(Object object)
、wx.getUserInfo(Object object)
、UserInfo
。使用頻率非常高的介面,常用於小程式中獲取登入者個人公開資料。wx.authorizeForMiniProgram(Object object)
、wx.authorize(Object object)
除上述列出的子類介面,還有收貨地址、生物認證……等諸多子類 API
,有興趣者可以自行了解。
登入
介面中有 3
個 API
,對於開發者來說,使用頻率較高的是 login
介面,此環節將重點介紹此介面。
非本文特別關注的介面,會簡略帶過。
wx.pluginLogin(Object args)
:此介面只能在外掛中可以呼叫,呼叫此介面獲得外掛使用者的標誌憑證code
,外掛可使用此憑證換取用於識別使用者的唯一標識 OpenpId
。
使用者不同、宿主小程式不同或外掛不同的情況下,該標識均不相同,即當且僅當同一個使用者在同一個宿主小程式中使用同一個外掛時,OpenpId
才會相同。
對於一般開發者,此 介面用的不是很多,具體使用細節在此處也不做過多複述。
什麼是 OpenId
?
當微信使用者登入公眾號或小程式時,微信平臺為每一個微信登入者分配的一個唯一識別符號號。
wx.login(Object object)
功能描述:
開發者使用此介面可以獲取到微信登入者
的登入憑證(code)
。
登入憑證
具有臨時性,也就是每次呼叫時都會不一樣,所以code
只能使用一次。
開發者可以通過臨時code
,再向微信介面伺服器索取登入者的唯一識別符號 OpenId
、微信開發平臺賬號的唯一標識 UnionID
(需要當前小程式已係結到微信開放平臺帳號)、以及對談金鑰 session_key
。
那麼,獲取到的openId
和session_key
對於開發者而言,有什麼實質性的意義?
OpenId
的唯一性特點,可以在微信使用者第一次登入時,把OpenID
儲存在資料庫或快取中,在後續登入時,只需要檢查使用者的 OpenId
是否存在於資料庫或快取中,便能實現自動登入功能。session_key
也稱對談金鑰,用來解密微信登入者的敏感資料。後文將詳細介紹。
如何獲取OpenId
?
現通過一個簡單案例,實現微信小程式端與開發者伺服器之間的資料互動。以此瞭解開發者伺服器如何通過微信小程式傳遞過來的使用者臨時 code
換取到登入者的更多資訊。
實現之前,先通過一個簡易演示圖瞭解其過程。
簡單描述整個請求過程:
wx.login
介面獲取到臨時登入憑證 code
。wx.request
介面向開發者伺服器傳送 http
請求,需要把登入憑證 code
一併行送過去。code
以及開發者憑證資訊向微信介面伺服器
索取微信登入者的 openId
和session_key
。簡而言之,就是 3
者(微信小程式、開發者伺服器、微信介面伺服器)之間的一個擊鼓傳花遊戲。
開發流程:
第一步:專案結構分析
完整的系統由 2
個部分組成:
微信小程式端 APP
。
如對微信小程式開發不是很瞭解,請先閱讀官方提供的相關檔案。
伺服器端應用程式。
本文的伺服器端應用程式基於 Spring Boot
開發平臺。
本專案結構是標準的前後端分離模式,微信小程式是前端應用,伺服器端應用程式為後臺應用。
第二步:新建微信小程式(前端應用)
開啟微信開發工具,新建一個名為 guokeai
的小程式專案 ,專案會初始化一個index
頁面。在 index.js
中編寫如下程式碼。
//index.js const app = getApp() const httpRequest = require("../../utils/request.js") Page({ data: { isHasUserInfo: null, userInfo: null }, //啟動時 onLoad: function () { let this_ = this /*** * 檢查微信使用者是否已經登入到後臺伺服器 * 已經登入的標誌,資料庫中存在 OPENID */ let code = null //呼叫 login 介面 wx.login({ success: (res) => { //得到登入使用者的臨時 code code = res.code //向開發者伺服器傳送請求 let api = "wx/getLoginCertificate" let config = { url: api, method: "GET", data: { code: code } } let promise = httpRequest.wxRequest(config) promise.then(res => { let isHas = null // 有沒有完整的微信登入者資訊 isHas = res.data == 0 ? false : true app.globalData.isHasUserInfo = isHas this_.setData({ isHasUserInfo: isHas }) }).catch(res => { console.log("fail", res) }); } }) } })
程式碼解釋:
onload
函數中呼叫 wx.login
介面,檢查使用者是否登入過。http://127.0.0.1:8080/wx/getLoginCertificate
是開發者伺服器
提供的對外處理微信使用者資訊的介面。httpRequest.wxRequest(config)
是自定義的封裝wx.request
介面的請求元件。function wxRequest(config) { //返回的資料型別 let dataType = config.dataType == null ? "json" : config.dataType; let responseType = config.responseType == null ? "text" : config.responseType; //伺服器基地址 let serverUrl = "http://127.0.0.1:8080/" //超時 let timeout = config.timeout == null ? 50000 : config.timeout; //目標地址,基地址+介面 let url = serverUrl + config.url; //資料提交方式 let method = config.method == null ? "GET" : config.method; //提交資料 let data = config.data == null ? null : config.data //頭資訊 let header = { // 預設值 'content-type': 'application/json', 'x-requested-with': 'XMLHttpRequest' } let sessionId = wx.getStorageSync('sessionId') if (sessionId) { header["cookie"] = sessionId } return new Promise(function (resolve, reject) { wx.request({ url: url, data: data, //返回的資料型別(json) dataType: dataType, enableCache: false, enableHttp2: false, enableQuic: false, method: method, header: header, responseType: responseType, timeout: timeout, success: (res) => { console.log("requestData", res) if (res.cookies != null && res.cookies.length != 0) wx.setStorageSync('sessionId', res.cookies[0]) resolve(res) }, fail: (res) => { console.log("requestException", res) reject(res) } }) }) }
第三步:建立開發者伺服器程式(後臺應用)
本文使用 spring boot
快速搭建後臺應用程式。在專案的 pom.xml
檔案中除了必要的依賴包外,還需要新增以下 的依賴包。
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency>
fastjson
是阿里雲
提供的開源 JSON
解析框架。
微信小程式
和開發者伺服器
構建的專案結構,是標準的前後端分離模式。
請求與響應時,資料互動常使用JSON
格式。這時使用 fastjson
作為json
解析器,當然,也可以選擇其它的類似解析器。
httpclient
是一個http
請求元件。mysql-connector-java
本文案例使用 MySQL
資料庫,需要載入相應的驅動包。mybatis-plus-boot-starter
,mybatis-plus
依賴包。在後臺應用中編寫處理器(響應)元件:
@RestController @RequestMapping("/wx") public class WxAction { @Autowired private IWxService wxService; /*** * 獲取到微信使用者的 OPENID */ @GetMapping("/getLoginCertificate") public String getLoginCertificate(@RequestParam("code") String code) throws Exception { WxUserInfo wxInfo = this.wxService.getLoginCertificate(code); //使用者不存在,或者使用者的資訊不全 return wxInfo==null || wxInfo.getNickName()==null?"0":"1"; }
程式碼解釋:
IWxService
是處理器依賴的業務元件,提供有 getLoginCertificate()
方法用來實現通過code
向微信介面伺服器
換取微信登入者的 openId
和session_key
。
編寫業務元件:
@Service public class WxService implements IWxService { @Override public WxUserInfo getLoginCertificate(String code) throws Exception { //請求地址 String requestUrl = WxUtil.getWxServerUrl(code); // 傳送請求 String response = HttpClientUtils.getRequest(requestUrl); //格式化JSON資料 WxUserInfo wxUserInfo = JSONObject.parseObject(response, WxUserInfo.class); //檢查資料庫中是否存在 OPENID WxUserInfo wxUserInfo_ = this.wxUserMapper.selectById(wxUserInfo.getOpenId()); if (wxUserInfo_ == null) { //資料庫中沒有使用者的 OPENID,新增到資料庫中 this.wxUserMapper.insert(wxUserInfo); } else { if (!wxUserInfo.getSessionKey().equals(wxUserInfo_.getSessionKey())) { //如果資料庫儲存的session_key和最新的session_key 不相同,則更新 wxUserInfo_.setSessionKey(wxUserInfo.getSessionKey()); this.wxUserMapper.updateById(wxUserInfo_); } } return wxUserInfo_; } }
程式碼解釋:
WxUtil
是自定義的一個工具元件,用來構建請求微信介面伺服器
的 url
。https://api.weixin.qq.com/sns/jscode2session
是微信介面伺服器
對外提供的介面,請求此介面時,需要提供 4
個請求資料。
appid
:小程式 appId。
secret
:小程式 appSecret。
js_code
:獲取到的微信登入者的臨時 code
。
grant_type
:授權型別,此處只需填寫 authorization_code
。
public class WxUtil { private final static String APP_ID = "微信小程式開發者申請的 appid"; private final static String APP_SECRET = "微信小程式開發者申請的 APP_SECRET"; // private final static String WX_LOGIN_SERVER_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code"; public static String getWxServerUrl(String code) throws IOException { String url = MessageFormat.format(WX_LOGIN_SERVER_URL, new String[]{APP_ID, APP_SECRET, code}); return url; } }
HttpClientUtils
也是一個自定義元件,用來向指定的伺服器傳送 http
請求。
public class HttpClientUtils { /** * GET請求 */ public static String getRequest(String url) throws Exception { //HttpClient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = null; try { HttpGet httpGet = new HttpGet(url); response = httpClient.execute(httpGet); //響應體 HttpEntity entity = response.getEntity(); if (entity != null) { //格式化響應體 return EntityUtils.toString(entity); } } catch (ClientProtocolException e) { throw e; } catch (IOException e) { throw e; } finally { response.close(); httpClient.close(); } return null; } }
WxUserInfo
是自定義的資料封裝類。微信介面伺服器
返回的資料是以JSON
格式組裝的,這裡需要格式成物件資料,便於在 java
中處理。本文使用 MyBatisPlus
運算元據庫,此類也對應資料庫中的gk_wx_user
表。
@Data @AllArgsConstructor @NoArgsConstructor @TableName("gk_wx_user") public class WxUserInfo { //OPEN_id @TableId(type = IdType.ASSIGN_ID, value = "open_id") private String openId; //對談金鑰 @TableField(value = "session_key") private String sessionKey; //頭像路徑 @TableField("avatar_url") private String avatarUrl; //城市 private String city; //國家 private String country; //性別 private String gender; //語言 private String language; //暱稱 @TableField("nick_name") private String nickName; //備註名或真實名 @TableField("real_name") private String realName; //省份 private String province; //學生ID @TableField("stu_id") private Integer stuId; }
MyBatis 資料庫對映元件:
@Repository public interface WxUserMapper extends BaseMapper<WxUserInfo> { }
第四步:測試。
先啟動後臺應用程式,再啟動微信小程式,可以在資料庫表中檢視到如下資訊。
微信使用者的openid
和session_key
已經儲存到後臺的資料庫表中。
官方檔案中,有一段對 session_key
的生命週期的描述。
session_key
的生命週期有不確定性,可以使用 wx.login
介面重新整理 session_key
。為了避免頻繁呼叫 wx.login
介面,可以通過呼叫 wx.checkSession(Object object)
介面判斷session_key
是否已經過期。session_key
有效期作為自身登入態有效期,也可以實現自定義的時效性策略。wx.checkSession
的功能,可以使用此介面判斷session_key
是否過期。
session_key
未過期。session_key
已過期。wx.login
介面僅能獲取到微信登入者的有限資料,如果想要獲取到登入者的更多個人資訊,可以使用使用者資訊介面中的相關API
。
wx.getUserProfile(Object object)
。獲取使用者資訊,頁面產生點選事件(例如 button
上 bindtap
的回撥中)後才可呼叫,每次請求都會彈出授權視窗,使用者同意後返回 userInfo
。wx.getUserInfo(Object object)
。和 wx.getUserProfile
的功能一樣,在基礎庫 2.10 的後續版本中,其功能已經被削弱。UserInfo
是使用者資訊封裝類。getUserProfile
是從 基礎庫2.10.4
版本開始支援的介面,該介面用來替換 wx.getUserInfo
,意味著官方不建議再使用getUserInfo
介面獲取使用者的個人資訊。
下圖是官方提供的 2
個介面的功能對比圖。
為了避免頻繁彈窗,可以在第一次獲取到使用者資訊後儲存在資料庫中以備以後所用。為了獲取到使用者的敏感資料,在後臺要通過getUserProfile
介面所獲取的資料進行解密操作。
wx.getUserProfile
下面通過具體程式碼講解如何儲存微信登入者的個人資料。先了解一下整個資料獲取的流程,這裡直接擷取官方提供的一張流程圖。
獲取微信登入者的個人資訊,需要經過 2
個步驟。
簽名效驗:
wx.getUserProfile
介面獲取資料時,介面會同時返回 rawData
、signature
,其中 signature = sha1( rawData + session_key )
。signature
、rawData
傳送到開發者伺服器進行校驗。伺服器利用使用者對應的 session_key
使用相同的演演算法計算出簽名 signature2
,比對signature
與 signature2
即可校驗資料的完整性。解密加密資料:
AES-128-CBC
,資料採用PKCS#7
填充。Base64_Decode(encryptedData)
。aeskey = Base64_Decode(session_key)
, aeskey
是16
位元組。Base64_Decode(iv)
,其中iv
由資料介面返回。具體編寫實現。
第一步:在微信小程式端編碼。
在index.wxml
頁面中新增一個按鈕,並註冊bindtap
事件。
<view> <button bindtap="getUserProfile">獲取使用者資料</button> </view>
在index.js
中新增一個名為getUserProfile
的事件回撥函數。為了避免不必要的彈窗,只有當後臺沒有獲取到個人資料時,才呼叫wx.getUserProfile
介面。
getUserProfile: function (e) { let this_ = this if (!this.data.isHasUserInfo) { //如果伺服器端沒有儲存完整的微信登入者資訊 wx.getUserProfile({ desc: '需要完善您的資料!', success: (res) => { this_.setData({ //小程式中用來顯示個人資訊 userInfo: res.userInfo, isHasUserInfo: true }) //再次登入,因為 session_key 有生命中週期 wx.login({ success(res_) { //儲存到伺服器端 let config = { url: "wx/wxLogin", method: "GET", data: { code: res_.code, //明文資料 rawData: res.rawData, //加密資料 encryptedData: res.encryptedData, iv: res.iv, //數位簽章 signature: res.signature } } let promise = httpRequest.wxRequest(config) promise.then(res => { //返回 console.log("wxLogin", res) }).catch(res => { console.log("fail", res) }); } }) } }) } }
伺服器端程式碼:
在pom.xml
檔案中新增如下依賴包,用來解密資料。
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency>
在處理器類WxAction
中新增wxLogin
響應方法。
@RestController @RequestMapping("/wx") public class WxAction { @Autowired private IWxService wxService; /*** * * @param code * @param rawData * @param encryptedData * @param iv * @param signature * @return * @throws Exception */ @GetMapping("/wxLogin") public WxUserInfo wxLogin(@RequestParam("code") String code, @RequestParam("rawData") String rawData, @RequestParam("encryptedData") String encryptedData, @RequestParam("iv") String iv, @RequestParam("signature") String signature) throws Exception { WxUserInfo wxInfo = this.wxService.getWxUserInfo(code, rawData, encryptedData, iv, signature); return wxInfo; } }
業務程式碼:
小程式中傳遞過來的資料是經過base64
編碼以及加密的資料,需要使用 Base64
解碼字串,再使用解密演演算法解密資料。先提供一個解密方法。
public String decrypt(String session_key, String iv, String encryptData) { String decryptString = ""; //解碼經過 base64 編碼的字串 byte[] sessionKeyByte = Base64.getDecoder().decode(session_key); byte[] ivByte = Base64.getDecoder().decode(iv); byte[] encryptDataByte = Base64.getDecoder().decode(encryptData); try { Security.addProvider(new BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); //得到金鑰 Key key = new SecretKeySpec(sessionKeyByte, "AES"); //AES 加密演演算法 AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("AES"); algorithmParameters.init(new IvParameterSpec(ivByte)); cipher.init(Cipher.DECRYPT_MODE, key, algorithmParameters); byte[] bytes = cipher.doFinal(encryptDataByte); decryptString = new String(bytes); } catch (Exception e) { e.printStackTrace(); } return decryptString; }
具體獲取資料的業務實現:
@Override public WxUserInfo getWxUserInfo(@NotNull String code, @NotNull String rawData, @NotNull String encryptedData, @NotNull String iv, @NotNull String signature) throws Exception { //對談金鑰 WxUserInfo wxUserInfo = this.getLoginCertificate(code); String signature2 = DigestUtils.sha1Hex(rawData + wxUserInfo.getSessionKey()); if (!signature.equals(signature2)) { throw new Exception("數位簽章驗證失敗"); } //數位簽章驗證成功,解密 String infos = this.decrypt(wxUserInfo.getSessionKey(), iv, encryptedData); //反序列化 JSON 資料 WxUserInfo wxUserInfo_ = JSONObject.parseObject(infos, WxUserInfo.class); wxUserInfo_.setSessionKey(wxUserInfo.getSessionKey()); wxUserInfo_.setOpenId(wxUserInfo.getOpenId()); //更新資料庫 this.wxUserMapper.updateById(wxUserInfo_); return wxUserInfo_; }
測試,啟動微信小程式和後臺應用,在小程式中觸發按鈕事件。
在彈出的對話方塊中,選擇允許。
檢視後臺資料庫表中的資料。
能夠獲取到的微信登入者個人資訊都儲存到了資料庫表中。至於怎麼使用這些資料,可以根據自己的業務需要客製化。
微信開發平臺,提供有諸多介面,可以幫助開發者獲取到有用的資料。本文主要介紹 wx.login
和wx.getProfile
介面,因篇幅所限,不能對其它介面做詳細介紹 ,有興趣者可以查閱官方檔案。
官方檔案只會對介面功能做些介紹 ,如要靈活運用這些介面,還需要結合實際需要演練一下,如此方能有切身體會。
到此這篇關於Spring Boot+微信小程式開發平臺儲存微信登入者的個人資訊的文章就介紹到這了,更多相關springboot微信小程式內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45