Heim  >  Artikel  >  WeChat-Applet  >  Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

coldplay.xixi
coldplay.xixinach vorne
2020-10-28 17:24:423610Durchsuche

Heute stellt die Kolumne WeChat Mini Program Development das Front-End-Design und die Implementierung der Miniprogramm-Anmeldung vor.

1. Einleitung

Der Zweck eines solch sorgfältigen Designs für die Anmeldung/Registrierung besteht natürlich darin, diese als Grundfunktion der Anwendung robust genug zu machen, um eine Site-weite Blockierung zu vermeiden.

Gleichzeitig müssen wir vollständig darüber nachdenken, wie wir bei der Entwicklung neuer kleiner Programme die Wiederverwendungsfähigkeit schnell entfernen und wiederholte Fallstricke vermeiden können.

Das Anmelde- und Registrierungsmodul ist wie ein Eisberg. Wir glauben, dass es nur bedeutet: „Geben Sie Ihr Konto und Ihr Passwort ein, und schon sind Sie mit der Anmeldung fertig.“

Hier möchte ich mit allen hier einige Designerfahrungen und Ideen teilen, die ich gesammelt habe, nachdem ich kürzlich ein kleines Programm-Anmelde-/Registrierungsmodul abgeschlossen habe.

2. Geschäftsszenario

Beim Durchsuchen des Miniprogramms ist es aufgrund geschäftlicher Anforderungen häufig erforderlich, einige grundlegende Informationen des Benutzers einzuholen:

  1. WeChat-Spitzname
  2. WeChat-Mobiltelefon Anzahl

Produkte haben unterschiedliche Informationsanforderungen für Benutzer und verfügen über unterschiedliche Autorisierungsprozesse.

Der erste Typ ist in E-Commerce-Systemen üblich. Um das Multiplattform-Konto des Benutzers zu identifizieren, verwenden sie häufig ihre Mobiltelefonnummer, um einen Kontakt herzustellen. In diesem Fall muss der Benutzer eine Autorisierung durchführen die Mobiltelefonnummer.

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

Zweitens ist es für eine grundlegende Initialisierung der Benutzerinformationen häufig erforderlich, weitere Benutzerinformationen abzurufen, z. B. den WeChat-Spitznamen, unionId usw., und Sie müssen um Benutzerautorisierung bitten.

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

Der dritte Typ umfasst den ersten Typ und den zweiten Typ.

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

3. Konzept

Mit dem Ziel, eine Reihe universeller Mini-Programm-Login-Lösungen und -Dienste zu entwickeln, analysieren wir das Geschäft und ermitteln die Variablen.

Bevor Sie mit dem technischen Design beginnen, reden Sie über den nötigen Unsinn und führen Sie eine grundlegende Abstimmung einiger Konzepte durch.

2.1 Über „Login“

Login ist auf Englisch „login“ und das entsprechende Wort ist „logout“. Bevor Sie sich anmelden, müssen Sie ein Konto haben und sich „registrieren“ (oder sich anmelden).

Es wird gesagt, dass das ursprüngliche Produkt keine Anmelde-/Registrierungsfunktion hatte, aber es wurde nach und nach verfügbar, als mehr Leute es nutzten. Aufgrund der Bedürfnisse des Produkts selbst muss der „Benutzer“ identifiziert werden.

In der realen Gesellschaft hat jeder von uns eine Identitäts-ID: einen Personalausweis. Als ich 16 wurde, führte ich eine „Registrierung“ durch, als ich zum ersten Mal zum Büro für öffentliche Sicherheit ging, um meinen Personalausweis zu bekommen. Dann ging ich ins Internetcafé, um im Internet zu surfen, zog meinen Ausweis durch und führte ein „Anmelde“-Verhalten durch.

Für das Internet in der virtuellen Welt lautet dieses Identitätszertifikat also „Konto + Passwort“.

Übliche Anmelde-/Registrierungsmethoden sind:

  1. Konto- und Passwortregistrierung

    In den frühen Tagen des Internets gab es nur eine geringe Abdeckung für persönliche E-Mails und Mobiltelefone. Daher muss sich der Benutzer einen Kontonamen ausdenken. Wir registrieren ein QQ-Konto, das in dieser Form vorliegt.

    from 汽车之家

  2. Registrierung von E-Mail-Adressen

    Nach der Jahrtausendwende ist das PC-Internetzeitalter schnell populär geworden und wir haben alle unsere eigenen persönlichen E-Mail-Adressen erstellt. Darüber hinaus verfügt QQ auch über ein E-Mail-Konto. Da E-Mails persönlich und privat sind und Informationen kommunizieren können, haben die meisten Websites damit begonnen, E-Mail-Konten als Benutzernamen für die Registrierung zu verwenden. Während des Registrierungsvorgangs werden sie aufgefordert, sich bei der entsprechenden E-Mail-Adresse anzumelden, um nach Aktivierungs-E-Mails zu suchen und so sicherzustellen, dass wir Eigentümer der registrierten E-Mail-Adresse sind.

    from 支付宝

  3. Registrierung von Mobiltelefonnummern

    Nach der Popularität des Internets haben sich Smartphones und mobiles Internet rasant weiterentwickelt. Mobiltelefone sind zu einem unverzichtbaren Mobilgerät für jedermann geworden, und das mobile Internet ist tief in das moderne Leben aller Menschen integriert. Daher sind Mobiltelefonnummern im Vergleich zu E-Mails derzeit enger mit Einzelpersonen verknüpft, und es entstehen immer mehr mobile Anwendungen, und auch Registrierungsmethoden, die Mobiltelefonnummern als Benutzernamen verwenden, sind weit verbreitet.

    from 知乎

Bis 2020 erreichte die Zahl der WeChat-Nutzer 1,2 Milliarden. Nun, WeChat-Konten sind, zumindest in China, zum „Identitätszeichen“ der neuen Generation der Internetwelt geworden.

Für das WeChat-Applet ist es selbstverständlich, die WeChat-Konto-ID des aktuellen Benutzers zu kennen. WeChat ermöglicht es Miniprogrammanwendungen, sich stillschweigend bei unseren Miniprogrammanwendungen anzumelden, ohne dass der Benutzer es merkt. Dies wird oft als „stille Anmeldung“ bezeichnet.

Tatsächlich ist die Anmeldung des WeChat-Applets im Wesentlichen das gleiche Konzept wie die „Single Sign-On“ herkömmlicher Webanwendungen.

  1. Single Sign-On: Nach der Anmeldung an Site A können Site C und Site B eine schnelle „stille Anmeldung“ durchführen.
  2. Anmeldung beim WeChat-Miniprogramm: Wenn Sie sich in WeChat bei Ihrem WeChat-Konto anmelden, können Sie eine „stille Anmeldung“ im gesamten Miniprogramm-Ökosystem erreichen.

Da HTTP ursprünglich zustandslos ist, lautet der grundlegende allgemeine Ansatz der Branche für den Anmeldestatus:

  1. Cookie-Sitzung: Wird häufig in Browseranwendungen verwendet.
  2. Zugriffstoken: Wird häufig in Nicht-Browser-Anwendungen wie mobilen Endgeräten verwendet.

Im WeChat-Applet ist die „JS-Logikschicht“ keine Browserumgebung und es gibt natürlich kein Cookie, daher wird normalerweise die Methode access token verwendet. Cookie,那么通常会使用 access token 的方式。

2.2 关于「授权」

对于需要更进一步获取用的用户昵称、用户手机号等信息的产品来说。微信出于用户隐私的考虑,需要用户主动同意授权。小程序应用才能获取到这部分信息,这就有了目前流行的小程序「Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung」、「Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung」的交互了。

出于不同的用户信息敏感度不同的考虑,微信小程序对于不同的用户信息提供「授权」的方式不尽相同:

  1. 调用具体 API 方式,弹窗授权。
    1. 例如调用 wx.getLocation() 的时候,如果用户未授权,则会弹出地址授权界面。
    2. 如果拒绝了,就不会再次弹窗,wx.getLocation()直接返回失败。
  2. <button open-type="xxx"></button> 方式。
    1. 仅支持:用户敏感信息,用户手机号,需要配合后端进行对称加解密,方能拿到数据。
    2. 用户已拒绝,再次点击按钮,仍然会弹窗。
  3. 通过 wx.authorize(),提前询问授权,之后需要获取相关信息的时候不用再次弹出授权。

四. 详细设计

梳理清楚了概念之后,我们模块的划分上,可以拆分为两大块:

  1. 登录:负责与服务端创建起一个会话,这个会话实现静默登录以及相关的容错处理等,模块命名为:Session
  2. 授权:负责与用户交互,获取与更新信息,以及权限的控制处理等,模块命名为:Auth

3.1 登录的实现

3.1.1 静默登录

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

微信官方提供的登录方案,总结为三步:

  1. 前端通过 wx.login() 获取一次性加密凭证 code,交给后端。
  2. 后端把这个 code 传输给微信服务器端,换取用户唯一标识 openId 和授权凭证 session_key。(用于后续服务器端和微信服务器的特殊 API 调用,具体看:微信官方文档-服务端获取开放数据)。
  3. 后端把从微信服务器获取到的用户凭证与自行生成的登录态凭证(token),传输给前端。前端保存起来,下次请求的时候带给后端,就能识别哪个用户。

如果只是实现这个流程的话,挺简单的。

但要实现一个健壮的登录过程,还需要注意更多的边界情况:

  1. 收拢 wx.login() 的调用

    由于 wx.login() 会产生不可预测的副作用,例如会可能导致session_key失效,从而导致后续的授权解密场景中的失败。我们这里可以提供一个像 session.login() 的方法,掌握 wx.login() 控制权,对其做一系列的封装和容错处理。

  2. 调用的时机

    通常我们会在应用启动的时候( app.onLaunch()

    2.2 Über „Autorisierung“

    Für Produkte, die außerdem Benutzer-Spitznamen, Benutzer-Handynummern und andere Informationen erhalten müssen. Aus Gründen der Privatsphäre der Benutzer verlangt WeChat von den Benutzern, dass sie der Autorisierung aktiv zustimmen. Nur Miniprogramm-Anwendungen können diesen Teil der Informationen erhalten. Dabei handelt es sich um das Zusammenspiel der derzeit beliebten Miniprogramme „Autorisierte Benutzerinformationen“ und „Autorisierte Mobiltelefonnummer“. 🎜🎜Aufgrund der unterschiedlichen Sensibilität verschiedener Benutzerinformationen bieten WeChat-Miniprogramme „Autorisierung“ für unterschiedliche Benutzerinformationen auf unterschiedliche Weise: 🎜🎜🎜Aufruf spezifischer API-Methoden und Popup-Autorisierung. 🎜🎜Wenn beispielsweise wx.getLocation() aufgerufen wird und der Benutzer nicht autorisiert ist, wird die Adressautorisierungsschnittstelle angezeigt. 🎜🎜Bei Ablehnung wird das Fenster nicht erneut angezeigt und wx.getLocation() gibt direkt einen Fehler zurück. 🎜🎜🎜🎜<button open-type="xxx"></button> Methode. 🎜🎜Unterstützt nur: vertrauliche Benutzerinformationen und die Mobiltelefonnummer des Benutzers. Sie müssen mit dem Backend zusammenarbeiten, um die Daten symmetrisch zu ver- und entschlüsseln. 🎜🎜Der Benutzer hat es abgelehnt. Wenn Sie erneut auf die Schaltfläche klicken, wird das Popup-Fenster weiterhin angezeigt. 🎜🎜🎜🎜Verwenden Sie wx.authorize(), um im Voraus eine Autorisierung anzufordern. Es ist nicht nötig, die Autorisierung erneut aufzurufen, wenn Sie später relevante Informationen benötigen. 🎜🎜

    IV. Detailliertes Design

    🎜Nach dem Aussortieren der Konzepte können unsere Module in zwei Hauptteile unterteilt werden: 🎜🎜🎜Anmelden : Verantwortlich für die Erstellung einer Sitzung mit dem Server. Diese Sitzung implementiert die stille Anmeldung und die damit verbundene Fehlertoleranzverarbeitung. Das Modul heißt: Session🎜🎜Autorisierung: Verantwortlich für die Interaktion mit Benutzer, Informationen abrufen und aktualisieren sowie Berechtigungen steuern usw. Das Modul heißt: Auth🎜🎜

    3.1 Login-Implementierung

    3.1.1 Stille Anmeldung

    🎜WeChat login🎜🎜Die offizielle Login-Lösung von WeChat ist in drei Schritten zusammengefasst: 🎜🎜🎜Front-End-Passwx.login() Ruft den einmaligen Verschlüsselungszertifikatcode ab und übergibt ihn an das Backend. 🎜🎜Das Backend übermittelt diesen Code an den WeChat-Server im Austausch gegen die eindeutige Benutzerkennung openId und das Autorisierungszertifikat session_key. (Spezielle API-Aufrufe, die für nachfolgende serverseitige und WeChat-Server verwendet werden, siehe für Details: Offizielle WeChat-Dokumentation – serverseitige Erfassung offener Daten). 🎜🎜Das Backend übermittelt die vom WeChat-Server erhaltenen Benutzeranmeldeinformationen und die selbst generierten Anmeldeinformationen (Token) an das Frontend. Das Frontend speichert es und bringt es bei der nächsten Anfrage zum Backend, damit es identifizieren kann, um welchen Benutzer es sich handelt. 🎜🎜🎜Wenn Sie diesen Prozess einfach umsetzen, ist er ganz einfach. 🎜🎜Aber um einen robusten Anmeldeprozess zu implementieren, müssen Sie auf weitere Randfälle achten: 🎜🎜🎜🎜Reduzieren Sie den Aufruf von wx.login(): 🎜🎜 Da wx.login() unvorhersehbare Nebenwirkungen hervorruft, kann es beispielsweise dazu führen, dass session_key ungültig wird, was in nachfolgenden Autorisierungsentschlüsselungsszenarien zu Fehlern führt. Wir können hier eine Methode wie session.login() bereitstellen, um die Kontrolle über wx.login() zu übernehmen und eine Reihe von Kapselungs- und Fehlertoleranzverarbeitungen darauf durchzuführen. 🎜🎜🎜🎜Zeitpunkt des Aufrufs: 🎜🎜Normalerweise initiieren wir die stille Anmeldung, wenn die Anwendung startet ( app.onLaunch() ). Es tritt jedoch ein asynchrones Problem auf, das durch das Designproblem des Applet-Lebenszyklus verursacht wird: Beim Laden der Seite und beim Aufrufen einer Back-End-API, die einen Anmeldestatus erfordert, wird der vorherige asynchrone statische Anmeldevorgang möglicherweise nicht abgeschlossen, was zu einem Anforderungsfehler führt . 🎜

    Natürlich können Sie einen Anmeldeaufruf auch asynchron blockierend initiieren, wenn die erste Schnittstelle aufgerufen wird, die den Anmeldestatus erfordert. Dies erfordert eine gut gestaltete Schnittstellenschicht.

    Die detaillierten Gestaltungsideen für die beiden oben genannten Szenarien werden im Folgenden besprochen.

  3. Probleme bei gleichzeitigen Anrufen:

    In Geschäftsszenarien ist es unvermeidlich, dass mehrere Codes die Anmeldung auslösen müssen. In extremen Fällen initiieren diese mehreren Codes gleichzeitig Anrufe. Dies führt dazu, dass der Anmeldevorgang innerhalb kurzer Zeit mehrmals gestartet wird, obwohl die vorherige Anfrage noch nicht abgeschlossen wurde. In dieser Situation können wir den ersten Anruf blockieren und auf das Ergebnis nachfolgender Anrufe warten, genau wie bei der Kombination von Sperma und Eizellen.

  4. Probleme mit nicht abgelaufenen Anrufen:

    Wenn unser Anmeldestatus nicht abgelaufen ist und normal verwendet werden kann, besteht standardmäßig keine Notwendigkeit, den Anmeldevorgang einzuleiten. Zu diesem Zeitpunkt können wir zunächst prüfen, ob der Anmeldestatus standardmäßig verfügbar ist. Wenn nicht, können wir eine Anfrage initiieren. Dann können Sie auch einen Parameter ähnlich wie session.login({ force: true }) bereitstellen, um die Anmeldung zu erzwingen. session.login({ force: true })的参数去强行发起登录。

3.1.2 静默登录异步状态的处理

1. 应用启动的时候调用

因为大部分情况都需要依赖登录态,我们会很自然而然的想到把这个调用的时机放到应用启动的时候( app.onLaunch() )来调用。

但是由于原生的小程序启动流程中, AppPageComponent 的生命周期钩子函数,都不支持异步阻塞。

那么我们很容易会遇到 app.onLaunch 发起的「登录过程」在 page.onLoad 的时候还没有完成,我们就无法正确去做一些依赖登录态的操作。

针对这种情况,我们设计了一个Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung的工具:status

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

基于Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung,我们就可以编写这样的代码:

import { Status } from '@beautywe/plugin-status';// on app.jsApp({    status: {       login: new Status('login');
    },    onLaunch() {
        session            // 发起静默登录调用
            .login()            // 把Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung设置为 success
            .then(() => this.status.login.success())      
            // 把Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung设置为 fail
            .catch(() => this.status.login.fail());
    },
});// on page.jsPage({    onLoad() {      const loginStatus = getApp().status.login;      
      // must 里面会进行状态的判断,例如登录中就等待,登录成功就直接返回,登录失败抛出等。
      loginStatus().status.login.must(() => {        // 进行一些需要登录态的操作...
      });
    },
});复制代码

2. 在「第一个需要登录态接口」被调用的时候去发起登录

更进一步,我们会发现,需要登录态的更深层次的节点是在发起的「需要登录态的后端 API 」的时候。

那么我们可以在调用「需要登录态的后端 API」的时候再去发起「静默登录」,对于并发的场景,让其他请求等待一下就好了。

以 fly.js 作为 wx.request() 封装的「网络请求层」,做一个简单的例子:

// 发起请求,并表明该请求是需要登录态的fly.post('https://...', params, { needLogin: true });// 在 fly 拦截器中处理逻辑fly.interceptors.request.use(async (req)=>{  // 在请求需要登录态的时候
  if (req.needLogin !== false) {    // ensureLogin 核心逻辑是:判断是否已登录,如否发起登录调用,如果正在登录,则进入队列等待回调。
    await session.ensureLogin();    
    // 登录成功后,获取 token,通过 headers 传递给后端。
    const token = await session.getToken();    Object.assign(req.headers, { [AUTH_KEY_NAME]: token });
  }  
  return req;
});复制代码

3.1.3 自定义登录态过期的容错处理

当自定义登录态过期的时候,后端需要返回特定的状态码,例如:AUTH_EXPIREDAUTH_INVALID 等。

前端可以在「网络请求层」去监听所有请求的这个状态码,然后发起刷新登录态,再去重放失败的请求:

// 添加响应拦截器fly.interceptors.response.use(    (response) => {      const code = res.data;        
      // 登录态过期或失效
      if ( ['AUTH_EXPIRED', 'AUTH_INVALID'].includes(code) ) {      
        // 刷新登录态
        await session.refreshLogin();        
        // 然后重新发起请求
        return fly.request(request);
      }
    }
)复制代码

那么如果并发的发起多个请求,都返回了登录态失效的状态码,上述代码就会被执行多次。

我们需要对 session.refreshLogin() 做一些特殊的容错处理:

  1. 请求锁:同一时间,只允许一个正在过程中的网络请求。
  2. 等待队列:请求被锁定之后,调用该方法的所有调用,都推入一个队列中,等待网络请求完成之后共用返回结果。
  3. 熔断机制:如果短时间内多次调用,则停止响应一段时间,类似于 TCP 慢启动。

示例代码:

class Session {  // ....
  
  // 刷新登录保险丝,最多重复 3 次,然后熔断,5s 后恢复
  refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;
  refreshLoginFuseLocked = false;
  refreshLoginFuseRestoreTime = 5000;  // 熔断控制
  refreshLoginFuse(): Promise<void> {    if (this.refreshLoginFuseLocked) {      return Promise.reject('刷新登录-保险丝已熔断,请稍后');
    }    if (this.refreshLoginFuseLine > 0) {      this.refreshLoginFuseLine = this.refreshLoginFuseLine - 1;      return Promise.resolve();
    } else {      this.refreshLoginFuseLocked = true;      setTimeout(() => {        this.refreshLoginFuseLocked = false;        this.refreshLoginFuseLine = REFRESH_LOGIN_FUSELINE_DEFAULT;
        logger.info('刷新登录-保险丝熔断解除');
      }, this.refreshLoginFuseRestoreTime);      return Promise.reject('刷新登录-保险丝熔断!!');
    }
  }  // 并发回调队列
  refreshLoginQueueMaxLength = 100;
  refreshLoginQueue: any[] = [];
  refreshLoginLocked = false;  // 刷新登录态
  refreshLogin(): Promise<void> {    return Promise.resolve()    
      // 回调队列 + 熔断 控制
      .then(() => this.refreshLoginFuse())
      .then(() => {        if (this.refreshLoginLocked) {          const maxLength = this.refreshLoginQueueMaxLength;          if (this.refreshLoginQueue.length >= maxLength) {            return Promise.reject(`refreshLoginQueue 超出容量:${maxLength}`);
          }          return new Promise((resolve, reject) => {            this.refreshLoginQueue.push([resolve, reject]);
          });
        }        this.refreshLoginLocked = true;
      })      // 通过前置控制之后,发起登录过程
      .then(() => {        this.clearSession();
        wx.showLoading({ title: '刷新登录态中', mask: true });        return this.login()
          .then(() => {
            wx.hideLoading();
            wx.showToast({ icon: 'none', title: '登录成功' });            this.refreshLoginQueue.forEach(([resolve]) => resolve());            this.refreshLoginLocked = false;
          })
          .catch(err => {
            wx.hideLoading();
            wx.showToast({ icon: 'none', title: '登录失败' });            this.refreshLoginQueue.forEach(([, reject]) => reject());            this.refreshLoginLocked = false;            throw err;
          });
      });  // ...}复制代码</void></void>

3.1.4 微信 session_key 过期的容错处理

我们从上面的「静默登录」之后,微信服务器端会下发一个 session_key 给后端,而这个会在需要获取Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung的时候会用到。

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

session_key

3.1.2 Behandlung des asynchronen Status der stillen Anmeldung

1 Wird beim Start der Anwendung aufgerufen, da die meisten Situationen Abhängigkeiten im Anmeldestatus erfordern. Wir denken natürlich darüber nach, diesen Aufruf beim Start der Anwendung aufzurufen (app.onLaunch()).

Aufgrund des nativen Applet-Startvorgangs unterstützen die Lebenszyklus-Hook-Funktionen von App, Page und Component jedoch kein asynchrones Blockieren .

🎜Dann können wir leicht feststellen, dass der von app.onLaunch initiierte „Anmeldevorgang“ zum Zeitpunkt von page.onLoad noch nicht abgeschlossen ist und wir dies nicht können um einige Abhängigkeiten korrekt durchzuführen. 🎜🎜Für diese Situation haben wir ein Zustandsmaschinentool entwickelt: status🎜🎜state machine🎜🎜Basierend auf der Zustandsmaschine können wir Code wie diesen schreiben:🎜
// 定义检查 session_key 有效性的操作const ensureSessionKey = async () => {  const hasSession = await new Promise(resolve => {
    wx.checkSession({      success: () => resolve(true),      fail: () => resolve(false),
    });
  });  
  if (!hasSession) {
    logger.info('sessionKey 已过期,刷新登录态');    // 接上面提到的刷新登录逻辑
    return session.refreshLogin();
  }  return Promise.resolve();
}// 在发起请求的时候,先做一次确保 session_key 最新的操作(以 fly.js 作为网络请求层为例)const updatePhone = async (params) => {  await ensureSessionKey();  const res = await fly.post('https://xxx', params);
}// 添加响应拦截器, 监听网络请求返回fly.interceptors.response.use(    (response) => {      const code = res.data;        
      // 登录态过期或失效
      if ( ['DECRYPT_WX_OPEN_DATA_FAIL'].includes(code)) {        // 刷新登录态
        await session.refreshLogin();        
        // 由于加密场景的加密数据由用户点击产生,session_key 可能已经更改,需要用户重新点击一遍。
        wx.showToast({ title: '网络出小差了,请稍后重试', icon: 'none' });
      }
    }
)复制代码
🎜🎜2. Im „Kapitel Wenn an Wenn die Schnittstelle aufgerufen wird, die den Anmeldestatus erfordert, wird die Anmeldung initiiert. 🎜🎜🎜Darüber hinaus werden wir feststellen, dass der tiefere Knoten, der den Anmeldestatus erfordert, der Zeitpunkt ist, an dem die „Backend-API, die den Anmeldestatus erfordert“ initiiert wird. 🎜🎜 Dann können wir die „stille Anmeldung“ initiieren, wenn wir die „Backend-API, die den Anmeldestatus erfordert“ aufrufen. Lassen Sie bei gleichzeitigen Szenarien einfach andere Anfragen warten. 🎜🎜Verwenden Sie fly.js als „Netzwerkanforderungsschicht“, gekapselt durch wx.request(), und erstellen Sie ein einfaches Beispiel: 🎜
// 用户登录的阶段export enum AuthStep {  // 阶段一:只有登录态,没有用户信息,没有手机号
  ONE = 1,  // 阶段二:有用户信息,没有手机号
  TWO = 2,  // 阶段三:有用户信息,有手机号
  THREE = 3,
}复制代码

3.1.3 Fehlertolerante Verarbeitung des Ablaufs des benutzerdefinierten Anmeldestatus

🎜Wenn der benutzerdefinierte Anmeldestatus abläuft, muss das Backend einen bestimmten Statuscode zurückgeben, wie zum Beispiel: AUTH_EXPIRED, AUTH_INVALID warte. 🎜🎜Das Frontend kann den Statuscode aller Anfragen in der „Netzwerkanforderungsschicht“ überwachen, dann eine Aktualisierung des Anmeldestatus initiieren und dann die fehlgeschlagene Anfrage erneut abspielen: 🎜
// auth-flow componentComponent({  // ...
  
  data: {    // 默认情况下,只需要到达阶段二。
    mustAuthStep: AuthStep.TWO
  },  
  // 允许临时更改组件的需要达到的阶段。
  setMustAuthStep(mustAuthStep: AuthStep) {    this.setData({ mustAuthStep });
  },  
  // 根据用户当前的信息,计算用户处在授权的阶段
  getAuthStep() {    let currAuthStep;    
    // 没有用户信息,尚在第一步
    if (!session.hasUser() || !session.hasUnionId()) {
      currAuthStep = AuthStepType.ONE;
    }    // 没有手机号,尚在第二步
    if (!session.hasPhone()) {
      currAuthStep = AuthStepType.TWO;
    }    // 都有,尚在第三步
    currAuthStep = AuthStepType.THREE;    return currAuthStep;
  }  
  // 发起下一步授权,如果都已经完成,就直接返回成功。
  nextStep(e) {    const { mustAuthStep } = this.data;    const currAuthStep = this.updateAuthStep();  
    // 已完成授权
    if (currAuthStep >= mustAuthStep || currAuthStep === AuthStepType.THREE) {      // 更新全局的授权Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung,广播消息给订阅者。
      return getApp().status.auth.success();
    }    // 第一步:更新用户信息
    if (currAuthStep === AuthStepType.ONE) {      // 已有密文信息,更新用户信息
      if (e) session.updateUser(e);      // 更新到视图层,展示对应UI,等待获取用户信息
      else this.setData({ currAuthStep });      return;
    }    // 第二步:更新手机信息
    if (currAuthStep === AuthStepType.TWO) {      // 已有密文信息,更新手机号
      if (e) this.bindPhone(e);      // 未有密文信息,弹出获取窗口
      else this.setData({ currAuthStep });      return;
    }    console.warn('auth.nextStep 错误', { currAuthStep, mustAuthStep });
  },  
  // ...});复制代码
🎜 Wenn dann mehrere Anfragen gleichzeitig initiiert werden, erfolgt die Anmeldung Status wird zurückgegeben. Ungültiger Statuscode, der obige Code wird mehrmals ausgeführt. 🎜🎜Wir müssen eine spezielle Fehlertoleranzverarbeitung für session.refreshLogin() durchführen: 🎜
    🎜🎜Anfragesperre🎜: Es ist nur eine laufende Netzwerkanfrage gleichzeitig zulässig. 🎜🎜🎜Wartewarteschlange🎜: Nachdem die Anforderung gesperrt wurde, werden alle Aufrufe dieser Methode in eine Warteschlange verschoben und warten darauf, dass die Netzwerkanforderung abgeschlossen wird, um das Rückgabeergebnis zu teilen. 🎜🎜🎜Leistungsschaltermechanismus🎜: Bei mehrmaligem Aufruf innerhalb kurzer Zeit reagiert es für einen bestimmten Zeitraum nicht mehr, ähnlich wie beim langsamen TCP-Start. 🎜
🎜Beispielcode: 🎜
<view>

  <!-- 已完成授权 -->
  <block>
    <view>已完成授权</view>
  </block>

  <!-- 未完成授权,第一步:Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung -->
  <block>
    <user-container>
      <view>Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung</view>
    </user-container>
  </block>

  <!-- 未完成授权,第二步:Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung -->
  <block>
    <phone-container>
      <view>Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung</view>
    </phone-container>
  </block>
  </view>复制代码

3.1.4 Fehlertolerante Verarbeitung des Ablaufs des WeChat-Sitzungsschlüssels

🎜Nachdem wir mit der obigen „stillen Anmeldung“ begonnen haben, Der WeChat-Server Ein session_key wird an das Backend gesendet und dieser wird verwendet, wenn es notwendig ist, offene WeChat-Daten zu erhalten. 🎜🎜WeChat Open Data🎜🎜Und session_key ist zeitkritisch. Das Folgende stammt aus der offiziellen Beschreibung von WeChat: 🎜🎜🎜Session key session_key validity🎜🎜Wenn Entwickler darauf stoßen Wenn die Signaturüberprüfung oder -entschlüsselung fehlschlägt, weil der Sitzungsschlüssel falsch ist, beachten Sie bitte die folgenden Vorsichtsmaßnahmen in Bezug auf Sitzungsschlüssel. 🎜
  1. wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 auth.code2Session 接口更新服务器存储的 session_key。
  2. 微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
  3. 开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。
  4. 当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。

翻译成简单的两句话:

  1. session_key 时效性由微信控制,开发者不可预测。
  2. wx.login 可能会导致 session_key 过期,可以在使用接口之前用 wx.checkSession 检查一下。

而对于第二点,我们通过实验发现,偶发性的在 session_key 已过期的情况下,wx.checkSession 会概率性返回 true

社区也有相关的反馈未得到解决:

  • 小程序解密手机号,隔一小段时间后,checksession:ok,但是解密失败
  • wx.checkSession有效,但是解密数据失败
  • checkSession判断session_key未失效,但是解密手机号失败

所以结论是:wx.checkSession可靠性是不达 100% 的。

基于以上,我们需要对 session_key 的过期做一些容错处理:

  1. 发起需要使用 session_key 的请求前,做一次 wx.checkSession 操作,如果失败了刷新登录态。
  2. 后端使用 session_key 解密开放数据失败之后,返回特定错误码(如:DECRYPT_WX_OPEN_DATA_FAIL),前端刷新登录态。

示例代码:

// 定义检查 session_key 有效性的操作const ensureSessionKey = async () => {  const hasSession = await new Promise(resolve => {
    wx.checkSession({      success: () => resolve(true),      fail: () => resolve(false),
    });
  });  
  if (!hasSession) {
    logger.info('sessionKey 已过期,刷新登录态');    // 接上面提到的刷新登录逻辑
    return session.refreshLogin();
  }  return Promise.resolve();
}// 在发起请求的时候,先做一次确保 session_key 最新的操作(以 fly.js 作为网络请求层为例)const updatePhone = async (params) => {  await ensureSessionKey();  const res = await fly.post('https://xxx', params);
}// 添加响应拦截器, 监听网络请求返回fly.interceptors.response.use(    (response) => {      const code = res.data;        
      // 登录态过期或失效
      if ( ['DECRYPT_WX_OPEN_DATA_FAIL'].includes(code)) {        // 刷新登录态
        await session.refreshLogin();        
        // 由于加密场景的加密数据由用户点击产生,session_key 可能已经更改,需要用户重新点击一遍。
        wx.showToast({ title: '网络出小差了,请稍后重试', icon: 'none' });
      }
    }
)复制代码

3.2 授权的实现

3.2.1 组件拆分与设计

在用户信息和手机号获取的方式上,微信是以 <button open-type="'xxx'"></button> 的方式,让用户主动点击授权的。

那么为了让代码更解耦,我们设计这样三个组件:

  1. <user-contaienr getuserinfo="onUserInfoAuth"></user-contaienr>: 包装点击交互,通过 <slot></slot> 支持点击区域的自定义UI。
  2. <phone-container getphonennmber="onPhoneAuth"></phone-container> : 与 <user-container></user-container> 同理。
  3. <auth-flow></auth-flow>: 根据业务需要,组合 <user-container></user-container><phone-container></phone-container> 组合来定义不同的授权流程。

以开头的业务场景的流程为例,它有这样的要求:

  1. 有多个步骤。
  2. 如果中途断掉了,可以从中间接上。
  3. 有些场景中,只要求达到「用户信息授权」,而不需要完成「用户手机号」。

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

那么授权的阶段可以分三层:

// 用户登录的阶段export enum AuthStep {  // 阶段一:只有登录态,没有用户信息,没有手机号
  ONE = 1,  // 阶段二:有用户信息,没有手机号
  TWO = 2,  // 阶段三:有用户信息,有手机号
  THREE = 3,
}复制代码

AuthStep 的推进过程是不可逆的,我们可以定义一个 nextStep 函数来封装 AuthStep 更新的逻辑。外部使用的话,只要无脑调用 nextStep 方法,等待回调结果就行。

示例伪代码:

// auth-flow componentComponent({  // ...
  
  data: {    // 默认情况下,只需要到达阶段二。
    mustAuthStep: AuthStep.TWO
  },  
  // 允许临时更改组件的需要达到的阶段。
  setMustAuthStep(mustAuthStep: AuthStep) {    this.setData({ mustAuthStep });
  },  
  // 根据用户当前的信息,计算用户处在授权的阶段
  getAuthStep() {    let currAuthStep;    
    // 没有用户信息,尚在第一步
    if (!session.hasUser() || !session.hasUnionId()) {
      currAuthStep = AuthStepType.ONE;
    }    // 没有手机号,尚在第二步
    if (!session.hasPhone()) {
      currAuthStep = AuthStepType.TWO;
    }    // 都有,尚在第三步
    currAuthStep = AuthStepType.THREE;    return currAuthStep;
  }  
  // 发起下一步授权,如果都已经完成,就直接返回成功。
  nextStep(e) {    const { mustAuthStep } = this.data;    const currAuthStep = this.updateAuthStep();  
    // 已完成授权
    if (currAuthStep >= mustAuthStep || currAuthStep === AuthStepType.THREE) {      // 更新全局的授权Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung,广播消息给订阅者。
      return getApp().status.auth.success();
    }    // 第一步:更新用户信息
    if (currAuthStep === AuthStepType.ONE) {      // 已有密文信息,更新用户信息
      if (e) session.updateUser(e);      // 更新到视图层,展示对应UI,等待获取用户信息
      else this.setData({ currAuthStep });      return;
    }    // 第二步:更新手机信息
    if (currAuthStep === AuthStepType.TWO) {      // 已有密文信息,更新手机号
      if (e) this.bindPhone(e);      // 未有密文信息,弹出获取窗口
      else this.setData({ currAuthStep });      return;
    }    console.warn('auth.nextStep 错误', { currAuthStep, mustAuthStep });
  },  
  // ...});复制代码

那么我们的 <auth-flow></auth-flow> 中就可以根据 currAuthStepmustAuthStep 来去做不同的 UI 展示。需要注意的是使用 <user-container></user-container><phone-container></phone-container> 的时候连接上 nextStep(e) 函数。

示例伪代码:

<view>

  <!-- 已完成授权 -->
  <block>
    <view>已完成授权</view>
  </block>

  <!-- 未完成授权,第一步:Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung -->
  <block>
    <user-container>
      <view>Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung</view>
    </user-container>
  </block>

  <!-- 未完成授权,第二步:Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung -->
  <block>
    <phone-container>
      <view>Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung</view>
    </phone-container>
  </block>
  </view>复制代码

3.2.2 权限拦截的处理

到这里,我们制作好了用来承载授权流程的组件 <auth-flow></auth-flow> ,那么接下来就是决定要使用它的时机了。

我们梳理需要授权的场景:

  1. 点击某个按钮,例如:购买某个商品。

    对于这种场景,常见的是通过弹窗完成授权,用户可以选择关闭。

    Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

  2. 浏览某个页面,例如:访问个人中心。

    对于这种场景,我们可以在点击跳转某个页面的时候,进行拦截,弹窗处理。但这样的缺点是,跳转到目标页面的地方可能会很多,每个都拦截,难免会错漏。而且当目标页面作为「小程序落地页面」的时候,就避免不了。

    这时候,我们可以通过重定向到授权页面来完成授权流程,完成之后,再回来。

    Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

那么我们定义一个枚举变量:

// 授权的展示形式export enum AuthDisplayMode {  // 以弹窗形式
  POPUP = 'button',  // 以页面形式
  PAGE = 'page',
}复制代码

我们可以设计一个 mustAuth 方法,在点击某个按钮,或者页面加载的时候,进行授权控制。

伪代码示例:

class Session {  // ...
  
  mustAuth({
    mustAuthStep = AuthStepType.TWO, // 需要授权的LEVEL,默认需要获取用户资料
    popupCompName = 'auth-popup',	// 授权弹窗组件的 id
    mode = AuthDisplayMode.POPUP, // 默认以弹窗模式
  } = {}): Promise<void> {    
    // 如果当前的授权步骤已经达标,则返回成功
    if (this.currentAuthStep() >= mustAuthStep) return Promise.resolve();    // 尝试获取当前页面的 <auth-popup></auth-popup> 组件实例
    const pages = getCurrentPages();    const curPage = pages[pages.length - 1];    const popupComp = curPage.selectComponent(`#${popupCompName}`);    // 组件不存在或者显示指定页面,跳转到授权页面
    if (!popupComp || mode === AuthDisplayMode.PAGE) {      const curRoute = curPage.route;      // 跳转到授权页面,带上当前页面路由,授权完成之后,回到当前页面。
      wx.redirectTo({ url: `authPage?backTo=${encodeURIComponent(curRoute)}` });      return Promise.resolve();
    }    
    // 设置授权 LEVEL,然后调用 <auth-popup> 的 nextStep 方法,进行进一步的授权。
    popupComp.setMustAuthStep(mustAuthStep);
    popupComp.nextStep();    // 等待成功回调或者失败回调
    return new Promise((resolve, reject) => {      const authStatus = getApp().status.auth;
      authStatus.onceSuccess(resolve);
      authStatus.onceFail(reject);
    });
  }  
  // ...}复制代码</auth-popup></void>

那么我们就能在按钮点击,或者页面加载的时候进行授权拦截:

Page({  onLoad() {
    session.mustAuth().then(() => {      // 开始初始化页面...
    });
  }  
  onClick(e) {
    session.mustAuth().then(() => {      // 开始处理回调逻辑...
    });
  }
})复制代码

当然,如果项目使用了 TS 的话,或者支持 ES7 Decorator 特性的话,我们可以为 mustAuth 提供一个装饰器版本:

export function mustAuth(option = {}) {  return function(
    _target,
    _propertyName,
    descriptor,  ) {    // 劫持目标方法
    const method = descriptor.value;    
    // 重写目标方法
    descriptor.value = function(...args: any[]) {      return session.mustAuth(option).then(() => {        // 登录完成之后,重放原来方法
        if (method) return method.apply(this, args);
      });
    };
  };
}复制代码

那么使用方式就简单一些了:

Page({
  @mustAuth();  onLoad() {    // 开始初始化页面...
  }
  
  @mustAuth();  onClick(e) {    // 开始处理回调逻辑...
  }
});复制代码

3.3. 前后端交互协议整理

作为一套可复用的小程序登录方案,当然需要去定义好前后端的交互协议。

那么整套登录流程下来,需要的接口有这么几个:

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

  1. 静默登录 silentLogin

    1. 入参:
      1. code: 产自 wx.login()
    2. 出参:
      1. token: 自定义登录态凭证
      2. userInfo: 用户信息
    3. 说明:
      1. 后端利用 code 跟微信客户端换取用户标识,然后注册并登录用户,返回自定义登录态 token 给前端
      2. token 前端会存起来,每个请求都会带上
      3. userInfo 需要包含nicknamephone字段,前端用于计算当前用户的授权阶段。当然这个状态的记录可以放在后端,但是我们认为放在前端,会更加灵活。
  2. 更新用户信息 updateUser

    1. 入参:
      1. nickname: 用户昵称
      2. encrypt: Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung相关的 iv, encryptedData
      3. 以及其他如性别地址等非必要字段
    2. 出参:
      1. userInfo:更新后的最新用户信息
    3. 说明:
      1. 后端解密Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung,获取隐蔽数据,如:unionId
      2. 后端支持更新包括 nickname等用户基本信息。
      3. 前端会把 userInfo 信息更新到 session 中,用于计算授权阶段。
  3. 更新用户手机号 updatePhone

    1. 入参:
      1. encrypt:Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung相关的 iv, encryptedData
    2. 出参:
      1. userInfo:更新后的最新用户信息
    3. 说明:
      1. 后端解密开放式局,获取手机号,并更新到用户信息中。
      2. 前端会把 userInfo 信息更新到 session 中,用于计算授权阶段。
  4. 解绑手机号 unbindPhone

    1. 入参:-
    2. 出参:-
    3. 说明:后端解绑用户手机号,成功与否,走业务定义的前后端协议。
  5. 登录 logout

    1. 入参:-

    2. 出参:-

    3. 说明:后端主动过期登录态,成功与否,走业务定义的前后端协议。

五. 架构图

最后我们来梳理一下整体的「登录服务」的架构图:

Verstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung

由「登录服务」和「底层建设」组合提供的通用服务,业务层只需要去根据产品需求,定制授权的流程 <auth-flow></auth-flow> ,就能满足大部分场景了。

六. 总结

本篇文章通过一些常见的登录授权场景来展开来描述细节点。

整理了「登录」、「授权」的概念。

然后分别针对「登录」介绍了一些关键的技术实现:

  1. Stille Anmeldung
  2. Asynchrone Statusverarbeitung der stillen Anmeldung
  3. Benutzerdefinierte Verarbeitung der Ablauffehlertoleranz des Anmeldestatus
  4. WeChatsession_keyAblauffehlertoleranzverarbeitung

Was die „Autorisierung“ betrifft, gibt es die Logik zum Entwerfen des UI-Teils. was auch einbezogen werden muss Zur Aufteilung von Komponenten:

  1. Komponentenaufteilung und -design
  2. Verarbeitung des Berechtigungsabfangens

Dann werden die Back-End-Schnittstellen, auf denen dieses Anmeldeautorisierungsschema basiert, aussortiert und die einfachste Referenz erstellt Protokoll liegt vor.

Abschließend habe ich aus der Perspektive „mit dem Ziel, eine Reihe universeller Mini-Programm-Login-Lösungen und -Dienste zu entwickeln“ die Schichtung auf architektonischer Ebene geklärt.

  1. Business-Anpassungsschicht
  2. Login-Service-Schicht
  3. Grundlegende Konstruktion

Verwandte kostenlose Lernempfehlungen: WeChat-Applet-Entwicklung

Das obige ist der detaillierte Inhalt vonVerstehen Sie das Front-End-Design und die Implementierung der WeChat-Miniprogramm-Anmeldung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen