1. 程式人生 > >微信小程式登入-openid和unionid

微信小程式登入-openid和unionid

本文轉自https://www.cnblogs.com/yaoyuqian/p/8203792.html

  我們一般都是先獲取到微信的 unionid,然後再通過 unionid 去登入自己的網站,就可以關聯到使用者在自己網站上的 user_id,但是在小程式登入中,有時候可以獲取到 unionid,有時候獲取不到,在獲取不到 unionid 的情況下,使用者無法正常登入網站。   UnionID機制說明:     如果開發者擁有多個移動應用、網站應用、和公眾帳號(包括小程式),可通過 unionid 來區分使用者的唯一性,因為只要是同一個微信開放平臺帳號下的移動應用、網站應用和公眾帳號(包括小程式),使用者的 unionid 是唯一的。換句話說,同一使用者,對同一個微信開放平臺下的不同應用,unionid 是相同的。   同一個微信開放平臺下的相同主體的 App、公眾號、小程式,如果使用者已經關注公眾號,或者曾經登入過App或公眾號,則使用者開啟小程式時,開發者可以直接通過 
wx.login
 獲取到該使用者UnionID,無須使用者再次授權。(解讀:使用者如果沒有登入過app,也沒有登入過公眾號,也沒有關注過公眾號的情況下,小程式中通過 wx.login 是獲取不到 unionid的)     簡而言之,微信針對不同的使用者在不同的應用下都有唯一的一個 openId, 但是要想確定使用者是不是同一個使用者,就需要靠 unionid 來區分。   通常自己的後臺都會有自己的一個使用者表,每個使用者有不同的 userid。也就是說同一個使用者在同一個微信開放平臺下的相同主體的應用對應著相同的 userid, unionid 以及不同的 openid。所以在使用者登入進來的時候,我們只能靠微信返回給我們的 unionid 去判斷是不是同一個使用者,再去關聯我們的使用者表,拿到對應的 user_id。   一般情況下(即在登入小程式之前,已經關注過公眾號或已經登入過公眾號或已經使用微信登入的方式登入過app),使用者通過以下兩步就正常成功登入網站。
1. 獲取code(登入憑證,用來換取openid及session_key等)
    wx.login({
      success: function(res){
         if(res.code){
             that.getNeededUserInfo(res.code);
          }else{
          console.log('獲取使用者登入態失敗!'+res.errMsg);
      }
    }
  })

2. 獲取使用者資訊(利用wx.login返回的code獲取使用者的資訊)
  getNeededUserInfo: function(code){
    wx.request({
      url: 'https://my.com/login',
      method: 'POST',
      data: {
        code: code // 後端通過這個code去呼叫微信的介面(https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code),傳入引數code、appid、appsecret後獲取到微信返回的unionid、openid及session_key等。(然後後端可以直接利用微信返回的資訊去關聯使用者在自己網站的user_id)
      },
      success: function(res){
        // 可以返回前端需要的使用者資訊(包括unionid、openid、user_id等)
      }
    })
  }
二般情況下(即在登入小程式之前,既沒有關注過公眾號,也沒有登入過公眾號,更沒有使用微信登入的方式登入過app),通過 wx.login 的到的 code 換不回 unionid 及 openid 等資訊。 解決思路:通過帶登入態的  wx.getUserInfo 獲取到使用者的加密資料 encryptedData 和加密演算法的初始向量iv,然後將 encryptdata、iv 以及 code傳給後端,後端再去通過接收到的encryptedData、iv以、code 以及之前的 session_key 解密出使用者的 openid、unionid 等。
加密資料解密演算法
以下是具體實現步驟:
1. 獲取code(登入憑證,用來換取openid及session_key等)
  wx.login({
    success:  function(res){
      if(res.code){
        that.getNeededUserInfo(res.code);
      }else{
        console.log('獲取使用者登入態失敗!'+res.errMsg);
      }
    }
  })

2. 獲取加密資料和加密演算法初始向量
舊版本基礎庫調取wx.getUserInfo()可以直接獲取到微信返回的encryptdata等完整資料,基礎庫更新之後,需要增加withCredentials屬性,並將屬性值設定為true時才可以獲取到除使用者基本資訊之外的encryptedData以及iv等資料。
需要注意的是:當withCredentials值為true時,要求此前有呼叫過wx.login且登入態尚未過期。
  getEncData:  function(){
    wx.getUserInfo({
      withCredentials: true,
      success: function(res){
        that.getNeededUserInfo( code,  res.encryptedData,  res.encryptedData );
      }
    })
  }

3. 獲取使用者資訊(利用wx.login返回的code獲取使用者的資訊)
  getNeededUserInfo:  function(code, enc, iv){
    wx.request({
      url: 'https://my.com/login',
      method: 'POST',
      data: {
        code: code,
        encryptedData: enc,
        iv: iv
      },
      success: function(res){
        // 可以返回前端需要的使用者資訊(包括unionid、openid、user_id等)
      }
    })
  }
實際專案中需要將以上兩種情況整合以後使用。   思路有兩種:     第一種:( 前端判斷是否有 unionid )在向後端上傳 code 並且後端返回資料以後,前端判斷返回值中是否有 unionid 或者 unionid 是否為 null,null 的情況下去呼叫帶有使用者登入態的wx.getUserInfo(),然後再將微信返回的  encryptedData 和 iv 返回給後端,後端解密出相應的資訊後再返回給前端;     第二種:( 後端判斷是否有 unionid )前端在呼叫 wx.getUserInfo() 時候帶著登入態,然後不管後臺能不能拿到 unionid,都把 encryptedData 和 iv 返回給後端,後端在拿到前端 code 之後去請求微信的介面拿 unionid,如果返回的 unionid 為空,再拿前端傳的 encryptedData、iv以及之前的 session_key 解密出 unionid。