用戶
 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

掃一掃,登錄網站

小程序社區 首頁 教程 實戰教程 查看內容

小程序登錄流程全解析

Rolan 2019-9-18 00:21

用戶登錄是一個系統的必備功能。而小程序的登錄流程和Web端又有一些不同,主要是要與微信服務器進行通信驗證。下面我們就來看下小程序具體的登錄流程。 1. 登錄流程 小程序可以通過微信官方提供的登錄能力方便地獲取 ...

用戶登錄是一個系統的必備功能。而小程序的登錄流程和Web端又有一些不同,主要是要與微信服務器進行通信驗證。下面我們就來看下小程序具體的登錄流程。

1. 登錄流程

小程序可以通過微信官方提供的登錄能力方便地獲取微信提供的用戶身份標識,快速建立小程序內的用戶體系。

2. 登錄邏輯:

  1. 調用 wx.login() 獲取 臨時登錄憑證 code,有效期為 5分鐘;(臨時登錄憑證 code 只能使用一次)

  2. 將臨時 code 傳到我們的后端,后端調用 auth.code2Session 接口,換取用戶唯一標識 OpenID 和 會話密鑰 session_key;( openid 是用戶唯一標識,session_key 能保證當前用戶進行會話操作的有效性)

    注意:獲取 session_key 出于安全性的考慮,要在后端調用。如果我們在前端通過 request 調用此接口,就不可避免的需要將我們小程序的appidsecret 和服務端下發的 session_key 暴露在外部,會給我們的業務安全帶來極大的風險。 session_key 擁有一定的時效性。用戶越久未使用小程序,用戶登錄態越有可能失效。反之如果用戶一直在使用小程序,則用戶登錄態一直保持有效。具體時效邏輯由微信維護,對開發者透明。開發者需要調用 wx.checkSession 接口檢測當前用戶登錄態是否有效。

  3. 后端自定義新的密鑰并關聯返回的 session_keyopenid,將新的密鑰返給前端,前端將其存儲在 storage 中。(會話密鑰 session_key 是對用戶數據進行 加密簽名 的密鑰。為了應用自身的數據安全,開發者服務器不應該把會話密鑰下發到小程序,也不應該對外提供這個密鑰,所以要定義新的密鑰)。 之所以存在storage中,是因為小程序沒有 cookie,相應的后端 set-cookie 在小程序中不起作用。

  4. 前端發送請求的時候,帶著密鑰,后端根據密鑰識別用戶身份,返回數據。

3. 遇到的問題

在接口報401錯誤時,對其做登錄處理,登錄成功后再次調用接口。這種情況下,多接口并行就會出現問題。 因為多接口都會調 wx.login 獲取 code 后再調后端的登錄接口,而登錄憑證 code 只能使用一次,這時候后端對多接口就會接收到不同的 code,返回的自定義密鑰就會有多個,不能保持統一。

處理的方案是后端在一定時間內對用戶自定義登錄態做緩存。接口調 wx.login 獲取 code 后再調后端的登錄接口時,判斷后端緩存中有無此用戶,如果沒有,返回新的密鑰,如果緩存中存在此用戶并在緩存有效時間內,就查找并返回之前的密鑰。

4. 具體代碼

checkSession: 檢查登錄態是否過期。 通過 wx.login 接口獲得的用戶登錄態擁有一定的時效性。用戶越久未使用小程序,用戶登錄態越有可能失效。反之如果用戶一直在使用小程序,則用戶登錄態一直保持有效。具體時效邏輯由微信維護,對開發者透明。開發者只需要調用 wx.checkSession 接口檢測當前用戶登錄態是否有效。 登錄態過期后開發者可以再調用 wx.login 獲取新的用戶登錄態。調用成功說明當前 session_key 未過期,調用失敗說明 session_key 已過期。

  checkSession: function () {
    return wx.pro.checkSession().then(res => {
      return Promise.resolve('result1')
    }).catch(err => {
      return this.login()
    })
  },
  
  login: function () {
    return wx.pro.login().then(res => {
      return Promise.resolve(res.code)
    }).then(res => {
      return this.getRequest({
        method: 'POST',
        url: "***/login",
        data: {
          code: res
        }
      })
    }).then(res => {
      let Cookie = res && res.header && res.header['Set-Cookie'] || '';
      Cookie = this.getCookie('cookie-key', Cookie)
      wx.setStorageSync('Cookie', Cookie)
      this.globalData.Cookie = Cookie
      return Promise.resolve('result2')
    }).catch(err => {
      console.log('loginErr', err)
    })
  },
  
  getCookie(name, cookie) {
    let arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    return (arr = cookie.match(reg)) ? unescape(arr[2]) : null;
  },
  
  getRequest: function (data, tryNum = 1) {
    let header = Object.assign({
      "Content-Type": "application/x-www-form-urlencoded",
    }, data.header)
    if (data.url !== '**/login') {
      header = Object.assign(header, {
        "Cookie": `cookie-key=${this.globalData.Cookie}`
      })
    }
    return new Promise((resolve, reject) => {
      wx.request({
        url: (data.mode !== 'debug' ? Env_config[envObj.env].api : '') + data.url,
        method: data.method || "GET",
        header: header,
        data: data.data,
        success: (res) => {
          if (res && res.statusCode === 200) {
            resolve(res)
          } else if (res.statusCode === 401) {
            wx.showToast({
              title: '登錄失效,請重新登錄',
              icon: 'none',
            })
            if (tryNum > maxTryNum) return null
            return this.login().then(res => {
              return this.getRequest(data, ++tryNum)
            }).then(res => resolve(res))
                .catch(err => {
                  reject(err)
                })
          } else {
            setTimeout(() => {
              wx.showToast({
                title: res && res.data && res.data.msg || '服務異常,請稍后重試',
                icon: 'none'
              })
            }, 0)
            reject(res)
          }
        },
        fail: (err) => {
          setTimeout(() => {
            wx.showToast({
              title: res && res.data && res.data.msg || '服務異常,請稍后重試',
              icon: 'none'
            })
          }, 0)
          reject(err)
        }
      })
    })
  },
復制代碼

在頁面中的用法也很簡單:

onLoad: function (options) {
  app.checkSession().then(res => {
    this.otherMethods()
  })
}

鮮花
鮮花
雞蛋
雞蛋
分享至 : QQ空間
收藏
原作者: 王樂平 來自: 掘金
致青春APP