Полный анализ процесса входа в апплет

Апплет WeChat

Логин пользователя является важной функцией системы. Процесс входа в апплет иWebМежду терминалами есть некоторые различия, в основном для проверки связи с сервером WeChat. Давайте посмотрим на конкретный процесс входа в апплет.

1. Процесс входа

Апплет может легко получить идентификатор пользователя, предоставленный WeChat, с помощью возможности входа в систему, предоставленной официальным лицом WeChat, и быстро установить пользовательскую систему в апплете.

小程序登录时序图

2. Логика входа:

  1. передачаwx.login()Получить временные учетные данные для входаcode, действительны в течение 5 минут; (временные учетные данные для входаcodeможно использовать только один раз)

  2. временноcodeПередайте его нашему бэкэнду, бэкенд звонитauth.code2Sessionинтерфейс, в обмен на уникальный идентификатор пользователяOpenIDи сеансовый ключsession_key;(openidуникальный идентификатор пользователя,session_keyЭто может гарантировать достоверность текущей операции сеанса пользователя)

    Примечание: получитьsession_keyИз соображений безопасности его следует вызывать на бэкэнде. Если мы пройдем в переднем концеrequestЧтобы вызвать этот интерфейс, необходимо преобразовать наш апплетappid,secretи доставлено серверомsession_keyВоздействие внешнего мира создаст большие риски для безопасности нашего бизнеса.session_keyИмеет определенную своевременность. Чем дольше пользователь не использовал апплет, тем больше вероятность того, что его статус входа в систему будет неудачным. С другой стороны, если пользователь использовал апплет, статус входа пользователя останется действительным. Конкретная логика своевременности поддерживается WeChat и прозрачна для разработчиков. Разработчики должны позвонитьwx.checkSessionИнтерфейс определяет, является ли текущий статус входа пользователя действительным.

  3. Серверная часть настраивает новый ключ и связывает возвращенный ключsession_keyа такжеopenid, возвращает новый ключ во внешний интерфейс, который сохраняет его вstorageсередина. (сеансовый ключsession_keyдля пользовательских данныхкриптографическая подписьключ. В целях безопасности собственных данных приложения сервер разработчика не должен передавать сеансовый ключ аплету, а также не должен предоставлять этот ключ извне, поэтому необходимо определить новый ключ). Причина, по которой он существует в хранилище, заключается в том, что у апплета нетcookie, соответствующий бэкендset-cookieНе работает в апплете.

  4. Когда внешний интерфейс отправляет запрос, он несет ключ, а задний конец идентифицирует пользователя в соответствии с ключом и возвращает данные.

3. Возникшие проблемы

Когда интерфейс сообщает об ошибке 401, войдите в него и снова вызовите интерфейс после успешного входа в систему. В этом случае будут проблемы с многоинтерфейсным параллелизмом. Поскольку несколько интерфейсов будут вызыватьwx.loginПолучатьcodeЗатем настройте интерфейс входа в систему и учетные данные для входа.codeЕго можно использовать только один раз, в это время бэкенд будет получать разныеcode, будет возвращено несколько пользовательских ключей, которые невозможно объединить.

Решение состоит в том, что серверная часть кэширует определяемое пользователем состояние входа в систему в течение определенного периода времени. настройка интерфейсаwx.loginПолучатьcodeПри настройке интерфейса входа в бэкэнд определите, существует ли пользователь в кеше бэкенда. Если нет, верните новый ключ. Если пользователь существует в кеше и в течение срока действия кеша, найдите и верните предыдущий ключ.

4. Специальный код

checkSession: проверьте, не истек ли срок действия статуса входа. пройти черезwx.loginСтатус входа пользователя, полученный интерфейсом, имеет определенную своевременность. Чем дольше пользователь не использовал апплет, тем больше вероятность того, что его статус входа в систему будет неудачным. С другой стороны, если пользователь использовал апплет, статус входа пользователя останется действительным. Конкретная логика своевременности поддерживается WeChat и прозрачна для разработчиков. Разработчикам нужно только позвонить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()
  })
}