SMS-Bestätigungscode-Anmeldefunktion basierend auf Antd Pro (Prozessanalyse)

SMS-Bestätigungscode-Anmeldefunktion basierend auf Antd Pro (Prozessanalyse)

Zusammenfassung

Kürzlich stieß ich bei der Entwicklung eines Projekts mit Antd Pro auf eine neue Anforderung: Die Anmeldung muss über einen SMS-Bestätigungscode auf der Anmeldeoberfläche erfolgen, anstatt die bisherige Anmeldemethode wie Benutzername und Kennwort zu verwenden.

Obwohl bei dieser Methode zusätzliche SMS-Gebühren anfallen, verbessert sie die Sicherheit erheblich. Antd verfügt nicht über eine integrierte Countdown-Schaltfläche.
Allerdings stellen die ProForm-Komponenten von antd pro Komponenten bereit, die sich auf SMS-Bestätigungscodes beziehen.
Die Komponentenbeschreibung finden Sie unter: https://procomponents.ant.design/components/form

Gesamtprozess

Der Anmeldevorgang per SMS-Bestätigungscode ist ganz einfach:

  1. SMS-Bestätigungscode anfordern (Client)
  2. SMS-Bestätigungscode generieren und Ablaufzeit des Bestätigungscodes festlegen (serverseitig)
  3. SMS-Schnittstelle aufrufen um Bestätigungscode zu senden (serverseitig)
  4. Melden Sie sich mit dem per SMS erhaltenen Bestätigungscode an (Client)
  5. Überprüfen Sie die Mobiltelefonnummer und den SMS-Bestätigungscode und stellen Sie nach der Überprüfung ein JWT-Token aus (serverseitig).

Frontend

Seitencode

importiere React, { useState } von 'react';
  importiere { connect } von „umi“;
   importiere {Nachricht} von „antd“;
  importiere ProForm, { ProFormText, ProFormCaptcha } aus '@ant-design/pro-form';
 importiere { MobileTwoTone, MailTwoTone } aus '@ant-design/icons';
  importiere { sendSmsCode } von '@/services/login';
 
 const Login = (Eigenschaften) => {
    const [countDown, handleCountDown] = useState(5);
    const { dispatch } = Requisiten;
    const [form] = ProForm.useForm();
    zurückkehren (
      <div
        Stil={{
          Breite: 330,
          Rand: "auto",
        }}
      >
        <ProForm
          form={form}
          Einsender={{
            Suchkonfiguration: {
              submitText: 'Anmelden',
            },
            rendern: (_, dom) => dom.pop(),
            SubmitButtonProps: {
              Größe: 'groß',
              Stil: {
                Breite: '100%',
              },
            },
            beim Senden: async () => {
              const fieldsValue = warte auf form.validateFields();
              console.log(FelderWert);
              warte auf Versand({
                Typ: 'login/login',
                Nutzlast: { Benutzername: FelderWert.mobile, SMS-Code: FelderWert.code },
              });
            },
          }}
        >
          <ProFormText
            FeldProps={{
              Größe: 'groß',
              Präfix: <MobileTwoTone />,
            }}
            Name = "Mobiltelefon"
            Platzhalter="Bitte geben Sie Ihre Telefonnummer ein"
            Regeln={[
              {
                erforderlich: wahr,
                Nachricht: 'Bitte geben Sie Ihre Telefonnummer ein',
              },
              {
                Muster: neuer RegExp(/^1[3-9]\d{9}$/, 'g'),
                Meldung: „Das Telefonnummernformat ist falsch“,
              },
            ]}
          />
          <ProFormCaptcha
            FeldProps={{
              Größe: 'groß',
              Präfix: <MailTwoTone />,
            }}
            countDown={countDown}
            captchaProps={{
              Größe: 'groß',
            }}
            Name = "Code"
            Regeln={[
              {
                erforderlich: wahr,
                Meldung: ,,Bitte geben Sie den Bestätigungscode ein! ',
              },
            ]}
            Platzhalter="Bitte geben Sie den Bestätigungscode ein"
            onGetCaptcha={async (mobile) => {
              wenn (!form.getFieldValue('mobile')) {
                message.error('Bitte geben Sie zuerst Ihre Telefonnummer ein');
                zurückkehren;
              }
              let m = form.getFieldsError(['mobile']);
              wenn (m[0].errors.length > 0) {
                Nachricht.Fehler(m[0].Fehler[0]);
                zurückkehren;
              }
              let response = warte auf sendSmsCode(mobile);
              if (response.code === 10000) message.success('Bestätigungscode erfolgreich gesendet!');
              sonst Nachricht.Fehler(Antwort.Nachricht);
            }}
          />
        </ProForm>
      </div>
    );
  };
  
  exportiere Standard connect()(Anmelden);

Bestätigungscode und Login-Dienst anfordern (src/services/login.js)

Importiere die Anfrage von „@/utils/request“;

  exportiere asynchrone Funktion login(params) {
  Rückgabeanforderung('/api/v1/login', {
     Methode: 'POST',
     Daten: Parameter,
   });
 }
 
  exportiere asynchrone Funktion sendSmsCode(mobile) {
    Anfrage zurückgeben(`/api/v1/send/smscode/${mobile}`, {
      Methode: 'GET',
    });
  }

Modell, das die Anmeldung handhabt (src/models/login.js)

importiere { stringify } aus 'Abfragezeichenfolge';
 importiere { Verlauf } von „umi“;
  importiere { login } von '@/services/login';
 importiere { getPageQuery } aus '@/utils/utils';
 importiere {Nachricht} von „antd“;
  importiere md5 von „md5“;
 
  const Modell = {
   Namespace: "Anmelden",
    Status: '',
    Anmeldetyp: '',
    Zustand: {
      Token: '',
    },
    Effekte:
      *login({ Nutzlast }, { aufrufen, setzen }) {
        Nutzlast.Client = "Administrator";
        // Nutzlast.Passwort = md5(Nutzlast.Passwort);
        const Antwort = Ertragsanruf (Anmeldung, Nutzlast);
        wenn (Antwortcode !== 10000) {
          Nachricht.Fehler(Antwort.Nachricht);
          zurückkehren;
        }
  
        // Token im lokalen Speicher festlegen
        wenn (window.localStorage) {
          window.localStorage.setItem('jwt-token', response.data.token);
        }
  
        Rendite setzen({
          Typ: 'changeLoginStatus',
          Nutzlast: {Daten: Antwort.Daten, Status: Antwort.Status, Anmeldetyp: Antwort.Anmeldetyp},
        }); // Anmeldung erfolgreich
  
        const urlParams = neue URL(window.location.href);
        const params = getPageQuery();
        let { umleiten } = Parameter;
  
        console.log(Umleitung);
        wenn (Umleitung) {
          const redirectUrlParams = neue URL(Umleitung);
  
          wenn (redirectUrlParams.origin === urlParams.origin) {
            Umleitung = Umleitung.substr(urlParams.origin.length);
  
            wenn (redirect.match(/^\/.*#/)) {
              Umleitung = Umleitung.substr(Umleitung.indexOf('#') + 1);
            }
          } anders {
            Fenster.Standort.href = "/home";
          }
        }
        Verlauf.Ersetzen(Umleitung || '/home');
      },
  
      abmelden() {
        const { redirect } = getPageQuery(); // Hinweis: Es können Sicherheitsprobleme auftreten. Bitte beachten Sie
  
        window.localStorage.removeItem('jwt-token');
        wenn (Fenster.Standort.Pfadname !== '/Benutzer/Anmeldung' && !Umleitung) {
          Verlauf.ersetzen({
            Pfadname: '/user/login',
            Suche: stringify({
              Umleitung: window.location.href,
            }),
          });
        }
      },
    },
    Reduzierstücke: {
      changeLoginStatus(status, { nutzlast }) {
        zurückkehren {
          ...Zustand,
          Token: Nutzlast.Daten.Token,
          Status: Nutzlast.Status,
          Anmeldetyp: payload.Anmeldetyp,
        };
      },
    },
  };
  Standardmodell exportieren;

hinteres Ende

Das Backend verfügt im Wesentlichen über zwei Schnittstellen, eine zum Versenden von SMS-Bestätigungscodes und eine zur Login-Bestätigung.

Routing-Code-Ausschnitt:

apiV1.POST("/login", authMiddleware.LoginHandler)
 apiV1.GET("/send/smscode/:mobile", controller.SendSmsCode)

Verarbeitung des SMS-Bestätigungscodes

  1. Bei der Verarbeitung von SMS-Verifizierungscodes sind einige Punkte zu beachten:
  2. Generieren Sie eine zufällige Nummer mit fester Länge und rufen Sie die SMS-Schnittstelle auf, um den Bestätigungscode zu senden. Speichern Sie den Bestätigungscode für zukünftige Überprüfungen.
  3. Generieren von Zahlen mit fester Länge

Der folgende Code generiert eine 6-stellige Zahl. Wenn die Zufallszahl weniger als 6 Ziffern hat, fügen Sie davor eine 0 hinzu.

r := rand.Neu(rand.NeueQuelle(Zeit.Jetzt().UnixNano()))
 Code := fmt.Sprintf("%06v", r.Int31n(1000000))

SMS-API anrufen

Dies ist ganz einfach. Rufen Sie es einfach gemäß der Anleitung der erworbenen SMS-Schnittstelle auf.

Prüfcode zur Verifizierung speichern

Hierbei ist zu beachten, dass der Verifizierungscode ein Ablaufdatum haben muss und ein Verifizierungscode nicht immer wieder verwendet werden kann.
Der Bestätigungscode für die temporäre Speicherung kann in der Datenbank oder in einem KV-Speicher wie Redis abgelegt werden. Der Einfachheit halber wird der Bestätigungscode mithilfe einer Kartenstruktur direkt im Speicher gespeichert.

Paket-Dienstprogramm

 importieren (
    "fmt"
   "Mathematik/Rand"
   "Synchronisieren"
  "Zeit"
  )

  Typ loginItem-Struktur {
    smsCode-Zeichenfolge
    smsCodeExpire int64
  }
  
  Typ LoginMap-Struktur {
    m Karte [Zeichenfolge] * LoginItem
    synchronisieren.Mutex
  }
  
  var lm *LoginMap
  
  Funktion InitLoginMap(resetTime int64, loginTryMax int) {
    lm = &LoginMap{
      m: make(map[string]*loginItem),
    }
  }
  
  func GenSmsCode(Schlüsselzeichenfolge) Zeichenfolge {
    r := rand.Neu(rand.NeueQuelle(Zeit.Jetzt().UnixNano()))
    Code := fmt.Sprintf("%06v", r.Int31n(1000000))
  
    wenn _, ok := lm.m[Schlüssel]; !ok {
      lm.m[Schlüssel] = &loginItem{}
    }
  
    v := lm.m[Schlüssel]
    v.smsCode = Code
    v.smsCodeExpire = time.Now().Unix() + 600 // Der Bestätigungscode läuft in 10 Minuten ab Rückgabecode
  }
  
  func CheckSmsCode(Schlüssel, Code-String) Fehler {
    wenn _, ok := lm.m[Schlüssel]; !ok {
      return fmt.Errorf("Bestätigungscode nicht gesendet")
    }
  
    v := lm.m[Schlüssel]
  
    // Ist der Bestätigungscode abgelaufen? if time.Now().Unix() > v.smsCodeExpire {
      return fmt.Errorf("Verifizierungscode (%s) ist abgelaufen", Code)
    }
  
    // Ist der Bestätigungscode korrekt, wenn Code != v.smsCode {
      return fmt.Errorf("Verifizierungscode (%s) falsch", Code)
    }
  
    Rückgabe Null
  }

Anmeldeüberprüfung

Der Anmeldebestätigungscode ist relativ einfach: Rufen Sie zuerst die oben genannte Methode CheckSmsCode auf, um zu überprüfen, ob er zulässig ist.
Nach der Überprüfung erhalten Sie Benutzerinformationen basierend auf der Mobiltelefonnummer, generieren ein JWT-Token und geben es an den Client zurück.

Häufig gestellte Fragen

Antd-Versionsproblem

Um ProForm von Antd Pro zu verwenden, müssen Sie die neueste Version von Antd verwenden, vorzugsweise >= v4.8, da sonst Inkompatibilitätsfehler in den Front-End-Komponenten auftreten.

Optimierbare Punkte

Die obige Implementierung ist relativ grob und die folgenden Aspekte können weiter optimiert werden:

Der Bestätigungscode muss seltener gesendet werden. Schließlich kostet das Senden von SMS-Nachrichten Geld. Der Bestätigungscode befindet sich direkt im Speicher und geht nach dem Neustart des Systems verloren. Sie können erwägen, ihn in einem Speicher wie Redis abzulegen.

Dies ist das Ende dieses Artikels über die SMS-Bestätigungscode-Anmeldefunktion (Prozessanalyse) basierend auf Antd Pro. Weitere relevante Antd Pro-Bestätigungscode-Anmeldeinhalte finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • AntDesign Pro + .NET Core implementiert eine JWT-basierte Login-Authentifizierungsfunktion
  • Detaillierte Erklärung zur Implementierung der Anmeldefunktion durch Kombination von React mit der Formularkomponente von Antd

<<:  Detaillierte Erläuterung der Linux-Dateiberechtigungen und Befehle zur Gruppenänderung

>>:  So verbinden Sie JDBC mit MySQL 5.7

Artikel empfehlen

So greifen Sie über die IP-Adresse auf MySql zu

1. Melden Sie sich bei MySQL an: mysql -u root -h...

Vue.js implementiert Kalenderfunktion

In diesem Artikelbeispiel wird der spezifische Co...

So installieren Sie die IonCube-Erweiterung mit Pagoda

1. Installieren Sie zuerst die Pagode Installatio...

Detaillierte Beispiele für die Ausführung von Zabbix-Remotebefehlen

Inhaltsverzeichnis eins. Umfeld zwei. Vorsichtsma...

MySQL erklärt das Prinzip und Beispiel zum Abrufen von Abfrageanweisungen

„explain“ wird verwendet, um Informationen zum Ab...

Detaillierte Erläuterung der allgemeinen Schritte zur SQL-Anweisungsoptimierung

Vorwort In diesem Artikel erfahren Sie hauptsächl...

Eine kurze Einführung in den MySQL-Dialekt

Wenn wir einmal von Datenbanken absehen, was ist ...

MySql 8.0.11-Winxp64 (kostenlose Installationsversion) Konfigurations-Tutorial

1. Entpacken Sie das Zip-Paket in das Installatio...

Detaillierte Erläuterung der Verwendung des Linux-Zeitbefehls

1. Befehlseinführung Mit „time“ werden die für di...

Implementierung eines einfachen Rechners mit Javascript

In diesem Artikelbeispiel wird der spezifische Ja...