<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      前言:


        在實(shí)際項(xiàng)目開(kāi)發(fā)中我們經(jīng)常會(huì)遇到賬號(hào)統(tǒng)一的問(wèn)題,如何在不同端或者是不同的登錄方式下保證同一個(gè)會(huì)員或者用戶賬號(hào)唯一(便于用戶信息的管理)。這段時(shí)間就有一個(gè)這樣的需求,之前有個(gè)客戶做了一個(gè)微信小程序商城(店主端的),然后現(xiàn)在又要做一個(gè)會(huì)員購(gòu)物端的小程序商場(chǎng)。首先之前用戶登錄憑證都是使用微信openid來(lái)做的唯一標(biāo)識(shí),而現(xiàn)在客戶需求是要做到用戶在會(huì)員端小程序跳轉(zhuǎn)到到店主端小程序假如之前該用戶微信是在店主端審核通過(guò)的用戶則不需要在進(jìn)行資料提交審核操作,直接登錄。所以,所以我們使用了UnionID來(lái)進(jìn)行關(guān)聯(lián),如下是我們現(xiàn)在項(xiàng)目的基本流程(畫(huà)的丑莫見(jiàn)怪)。



      說(shuō)說(shuō)UnionID機(jī)制:

        如果開(kāi)發(fā)者擁有多個(gè)移動(dòng)應(yīng)用、網(wǎng)站應(yīng)用、和公眾帳號(hào)(包括小程序),可通過(guò) UnionID
      來(lái)區(qū)分用戶的唯一性,因?yàn)橹灰峭粋€(gè)微信開(kāi)放平臺(tái)帳號(hào)下的移動(dòng)應(yīng)用、網(wǎng)站應(yīng)用和公眾帳號(hào)(包括小程序),用戶的 UnionID
      是唯一的。換句話說(shuō),同一用戶,對(duì)同一個(gè)微信開(kāi)放平臺(tái)下的不同應(yīng)用,unionid是相同的。

      官方UnionID機(jī)制詳細(xì)說(shuō)明:
      https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html

      <https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html>

      微信開(kāi)放平臺(tái)綁定小程序流程:

      登錄微信開(kāi)放平臺(tái) <https://open.weixin.qq.com/>?— 管理中心 — 小程序 — 綁定小程序(直接使用微信官方圖)



      微信小程序獲取UnoinID的兩種方式:

      調(diào)用接口?wx.getUserInfo,從解密數(shù)據(jù)(encryptedData)中獲取 UnionID(推薦使用):

      推薦使用原因:無(wú)需關(guān)注微信公眾號(hào)即可獲取到UnionID。

      調(diào)用接口wx.getUserInfo前提:用戶允許授權(quán)獲取用戶信息!

      開(kāi)發(fā)者后臺(tái)校驗(yàn)與解密開(kāi)放數(shù)據(jù):

        微信為了保證用戶信息,把用戶通過(guò)wx.getUserInfo接口獲取到的相關(guān)敏感信息進(jìn)行了加密。加密方式對(duì)稱加密(后面會(huì)提到),首先我們需要通過(guò)
      微信小程序登錄流程
      <https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html>
      獲取到用戶的session_key(會(huì)話密鑰),然后我們可以報(bào)獲取到的會(huì)話密鑰使用緩存存起來(lái),在通過(guò)用戶授權(quán)獲取用戶相關(guān)信息,如下是用戶授權(quán)成功獲取到的用戶信息:



      基本流程圖如下:



      ?

      ?

      (encryptedData)加密數(shù)據(jù)解密算法:

      開(kāi)發(fā)者如需要獲取敏感數(shù)據(jù),需要對(duì)接口返回的加密數(shù)據(jù)(encryptedData)?進(jìn)行對(duì)稱解密。 解密算法如下:

      * 對(duì)稱解密使用的算法為 AES-128-CBC,數(shù)據(jù)采用PKCS#7填充。
      * 對(duì)稱解密的目標(biāo)密文為 Base64_Decode(encryptedData)。
      * 對(duì)稱解密秘鑰 aeskey = Base64_Decode(session_key), aeskey 是16字節(jié)。
      * 對(duì)稱解密算法初始向量 為Base64_Decode(iv),其中iv由數(shù)據(jù)接口返回
      很遺憾的是微信居然沒(méi)有為我們大.Net提供解密算法demo,實(shí)屬讓人不算,最后自己根據(jù)網(wǎng)上的資料還是配上了符合微信對(duì)稱加密的解密算法。

      代碼實(shí)現(xiàn):

      首先關(guān)于session_key(會(huì)話密鑰)的獲取,請(qǐng)看下面的wx.login+code2Session 方式

      調(diào)用接口wx.getUserInfo獲取encryptedData(加密數(shù)據(jù))和iv(初始向量):
      // 用戶已經(jīng)授權(quán) wx.getUserInfo({ success: function(res) { console.log(res); var
      userInfo = res.userInfo//用戶基本信息 let sessionKey = wx.getStorageSync("session_key"
      );//臨時(shí)會(huì)話密鑰,通過(guò)小程序登錄流程獲取到的 //請(qǐng)求.net webapi解密接口 wx.request({ url: '
      https://www.xxxtest.com/api/User_oAuth/DecryptSensitiveData', data: {
      sessionKey:sessionKey, encryptedData:res.encryptedData, iv:res.iv }, header: {'
      content-type': 'application/json' // 默認(rèn)值 }, success (res) { //解密返回過(guò)來(lái)的UnionID
      console.log(res.data) } }) } }) })
      .Net WebApi 解密數(shù)據(jù)接口:
      /// <summary> /// 解密微信對(duì)稱加密數(shù)據(jù),獲取用戶聯(lián)合運(yùn)營(yíng)編號(hào) /// </summary> /// <param
      name="sessionKey">臨時(shí)會(huì)話秘鑰</param> /// <param name="encryptedData">微信用戶敏感加密數(shù)據(jù)
      </param> /// <param name="iv">解密初始向量</param> /// <returns></returns> [HttpGet]
      public IHttpActionResult DecryptSensitiveData(string sessionKey,string
      encryptedData,string iv) { try { var getUnionId=
      DecryptByAesBytes(encryptedData, sessionKey, iv);return Json(new { code =1, msg=
      "解密成功",result= getUnionId }); } catch (Exception ex) { return Json(new { code =
      0, msg = "解密失敗,原因:"+ex.Message }); } } #region AES對(duì)稱解密 /// <summary> /// AES解密
      /// </summary> /// <param name="encryptedData">待解密的字節(jié)數(shù)組</param> /// <param
      name="sessionKey">解密密鑰字節(jié)數(shù)組</param> /// <param name="iv">IV初始化向量字節(jié)數(shù)組</param> ///
      <param name="cipher">運(yùn)算模式</param> /// <param name="padding">填充模式</param> ///
      <returns></returns> private static string DecryptByAesBytes(string
      encryptedData,string sessionKey, string iv) { try { //非空驗(yàn)證 if (!string
      .IsNullOrWhiteSpace(encryptedData) && !string.IsNullOrWhiteSpace(sessionKey) &&
      !string.IsNullOrWhiteSpace(iv)) { var decryptBytes =
      Convert.FromBase64String(encryptedData.Replace(' ', '+')); var keyBytes =
      Convert.FromBase64String(sessionKey.Replace(' ', '+')); var ivBytes =
      Convert.FromBase64String(iv.Replace(' ', '+')); var aes = new
      AesCryptoServiceProvider { Key= keyBytes, IV = ivBytes, Mode = CipherMode.CBC,
      Padding= PaddingMode.PKCS7 }; var outputBytes =
      aes.CreateDecryptor().TransformFinalBlock(decryptBytes,0, decryptBytes.Length);
      var decryptResult = Encoding.UTF8.GetString(outputBytes); dynamic decryptData =
      JsonConvert.DeserializeObject(decryptResult,new { unionid = "" }.GetType());
      JJHL.Utility.Loghelper.WriteLog("AES對(duì)稱解密結(jié)果為:" + decryptResult); return
      decryptData.unionid; }else { return ""; } } catch (Exception e) {
      JJHL.Utility.Loghelper.WriteLog("AES對(duì)稱解密失敗原因:" + e.Message); return ""; } }
      #endregion
      所遇異常:參數(shù)使用Convert.FromBase64String轉(zhuǎn)化時(shí),提示“Base-64字符數(shù)組的無(wú)效長(zhǎng)度” 的問(wèn)題:

      原因:加密參數(shù)中的"+"通過(guò)地址欄傳過(guò)來(lái)時(shí),后臺(tái)會(huì)解析為空格(遇到的概率比較小)。

      解決:最好的做法是 使用encryptedData.Replace("+",
      "%2B")先將空格編碼,然后再作為參數(shù)傳給另一頁(yè)面?zhèn)鬟f,這樣頁(yè)面在提取參數(shù)時(shí)才會(huì)將“%2B”解碼為加號(hào).但這兒為了簡(jiǎn)化,將空格直接還原為"+"或者是直接在后臺(tái)將空格替換為“+”encryptedData.Replace('?
      ', '+');

      直接通過(guò)?wx.login
      <https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html>
      ?+?code2Session?獲取到該用戶 UnionID:

      其實(shí)這個(gè)方式就是實(shí)現(xiàn)了小程序的登錄流程,微信官方詳細(xì)說(shuō)明:


      https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

      <https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html>

      優(yōu)點(diǎn):無(wú)需用戶授權(quán)。

      前提:用戶需要關(guān)注該微信公眾號(hào)。


      小程序端調(diào)用接口wx.login獲取code憑證,在通過(guò)請(qǐng)求auth.code2Session接口獲取用戶信息(UnionID,openid,session_key會(huì)話密鑰)兩種方式:

      1.直接通過(guò)wx.login請(qǐng)求到code憑證后,在請(qǐng)求該地址獲取用戶信息:

      GET:https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
      詳細(xì)說(shuō)明請(qǐng)看微信官方文檔(代碼略):
      https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

      <https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html>

      2.通過(guò)請(qǐng)求wx.login獲取code憑證,在向.net webapi后端請(qǐng)求code2Session接口:

      原因:因?yàn)槲覀冃枰獙?duì)獲取的用戶信息做相關(guān)業(yè)務(wù)邏輯處理。

      微信小程序端代碼:
      /** *封裝用戶promise登錄,通過(guò)code憑證獲取用戶信息(UnionID,openid,session_key會(huì)話密鑰) */
      userLogin: function() {var that = this; //定義promise方法 return new
      Promise(function(resolve, reject) {//調(diào)用登錄接口 wx.login({ success: function(res) {
      if (res.code) { console.log("用戶登錄授權(quán)code為:" + res.code); //
      調(diào)用wx.request請(qǐng)求傳遞code憑證換取用戶openid,并獲取后臺(tái)用戶信息 wx.request({ url: '
      https://www.xxxx.xxx.api/User_oAuth/GetUserInfo',//后臺(tái)請(qǐng)求用戶信息方法 data: { code:
      res.code//code憑證 }, header: { 'content-type':'application/json' // 默認(rèn)值 },
      success(res) { console.log(res.data)if (res.data.errcode == 0) { //存入session緩存中
      console.log(res.data.openid);//微信用戶唯一標(biāo)識(shí) console.log(res.data.UnionID);//
      微信開(kāi)發(fā)平臺(tái)聯(lián)合ID console.log(res.data.session_key);//會(huì)話密鑰
      //***注意****
      //注意:這里是直接把session_key緩存起來(lái),在上面wx.getUserInfo會(huì)使用到
      wx.setStorageSync("session_key",res.data.session_key); //promise機(jī)制放回成功數(shù)據(jù)
      resolve(res.data);
      } else
      { reject('error'); }
      }, fail: function(res)
      {
      reject(res);
      wx.showToast({ title: '系統(tǒng)錯(cuò)誤' })
      }, complete: () => { } //complete接口執(zhí)行后的回調(diào)函數(shù),無(wú)論成功失敗都會(huì)調(diào)用
      }) } else
      {
      reject("error");
      }}
      }) })}
      .Net WebApi 請(qǐng)求用戶信息接口:
      /// <summary> /// 獲取用戶信息 /// </summary> /// <param name="code">信息數(shù)據(jù)code憑證
      </param> /// <returns></returns> [HttpGet] public IHttpActionResult
      GetUserInfo(string code) { string AppSecret = "小程序秘鑰"; string AppId = "應(yīng)用程序標(biāo)識(shí)";
      try { //請(qǐng)求目標(biāo)地址和參數(shù)(authorization_code授權(quán)類型,此處只需填寫(xiě) authorization_code) string
      OauthUrl ="https://api.weixin.qq.com/sns/jscode2session?appid=" + AppId + "
      &secret=" + AppSecret + "&js_code=" + code + "&grant_type=authorization_code";//
      序列化解析數(shù)據(jù) var Result = HttpGet(OauthUrl); return Json(new { openid =
      Result.openid, errcode = Result.errcode, UnionID = Result.unionid, session_key =
      Result.session_key }); }catch (Exception ex) { return Json(new { errcode = 1,
      msg ="獲取用戶信息失敗" + ex.Message }); } } /// <summary> /// 請(qǐng)求code2Session接口獲取用戶信息
      /// </summary> /// <param name="requestDataAndUrl">目標(biāo)地址和參數(shù)</param> ///
      <returns></returns> public WxOauthModle HttpGet(string requestDataAndUrl) {
      HttpWebRequest request= (HttpWebRequest)WebRequest.Create(requestDataAndUrl);
      request.Method= "GET"; request.ContentType = "text/html;charset=UTF-8";
      HttpWebResponse response= (HttpWebResponse)request.GetResponse(); Stream
      myResponseStream= response.GetResponseStream(); StreamReader myStreamReader =
      new StreamReader(myResponseStream, Encoding.UTF8); string retString =
      myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close();
      return JsonConvert.DeserializeObject<WxOauthModle>(retString); } public class
      WxOauthModle {/// <summary> /// 用戶唯一標(biāo)識(shí) /// </summary> public string openid { get
      ;set; } /// <summary> /// 會(huì)話秘鑰 /// </summary> public string session_key { get;
      set; } /// <summary> /// 聯(lián)立編號(hào) /// </summary> public string unionid { get; set; }
      /// <summary> /// 錯(cuò)誤碼 /// </summary> public int errcode { get; set; } ///
      <summary> /// 錯(cuò)誤信息 /// </summary> public string errmsg { get; set; } }
      關(guān)于微信網(wǎng)頁(yè)開(kāi)發(fā)通過(guò)UnionID機(jī)制解決用戶在不同公眾號(hào),或在公眾號(hào)、移動(dòng)應(yīng)用之間帳號(hào)統(tǒng)一問(wèn)題:

      詳情說(shuō)明請(qǐng)點(diǎn)擊:https://www.cnblogs.com/Can-daydayup/p/9368844.html
      <https://www.cnblogs.com/Can-daydayup/p/9368844.html>

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問(wèn)題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          十八禁网站免费观看 | 小早川怜子丰满人妻第96集 | 快播污视频 | 午夜视频二区 | 欧美不卡日韩人妻一区 | 99香蕉视频 | 高清日韩欧美 | 亚洲色婷婷AV | 熟女操逼网 | 不要钱的黄色app |