Aktivieren der QR-Code-Generierung für TOTP-Authentifikator-Apps in einer ASP.NET Core Blazor Web-App

In diesem Artikel wird erläutert, wie Sie eine ASP.NET Core Blazor Web App mit QR-Codegenerierung für TOTP-Authentifikator-Apps konfigurieren.

Eine Einführung in die zweistufige Authentifizierung (2FA) mit Authentifikator-Apps mit einem zeitbasierten Einmalkennwortalgorithmus (TOTP) finden Sie unter Aktivieren der QR-Codegenerierung für TOTP-Authentifikator-Apps in ASP.NET Core.

Erstellen eines Gerüsts für die Enable Authenticator-Komponente in der App

Befolgen Sie die Anweisungen in GerüstIdentity in ASP.NET Core-Projekten, um ein Gerüst für Pages\Manage\EnableAuthenticator in der App zu erstellen.

Hinweis

Obwohl nur die Komponente für das EnableAuthenticator Gerüst in diesem Beispiel ausgewählt ist, fügt das Gerüst zurzeit alle Identity Komponenten zur App hinzu. Darüber hinaus können Ausnahmen während des Gerüsts in der App ausgelöst werden. Wenn Ausnahmen auftreten, wenn Datenbankmigrationen auftreten, beenden Sie die App, und starten Sie die App für jede Ausnahme neu. Weitere Informationen finden Sie unter Gerüst für Ausnahmen für Blazor Web App (dotnet/ScaffoldingNr. 2694).

Haben Sie Geduld, während Migrationen ausgeführt werden. Je nach Geschwindigkeit des Systems kann es bis zu einer Minute oder zwei dauern, bis Datenbankmigrationen abgeschlossen sind.

Weitere Informationen finden Sie unter Gerüst Identity in ASP.NET Core-Projekten. Anleitungen zur Verwendung der .NET CLI anstelle von Visual Studio finden Sie unter dotnet aspnet-codegenerator command.

Hinzufügen von QR-Codes zur 2FA-Konfigurationsseite

Diese Anweisungen verwenden shim Sangminsqrcode.js: Browserübergreifender QRCode-Generator für JavaScript (davidshimjs/qrcodejs GitHub-Repository).

Laden Sie die qrcode.min.js Bibliothek in den wwwroot Ordner des Serverprojekts der Lösung herunter. Die Bibliothek hat keine Abhängigkeiten.

Platzieren Sie in der App Komponente (Components/App.razor) einen Bibliotheksskriptverweis nach Blazors <script>Tag:

<script src="qrcode.min.js"></script>

Die EnableAuthenticator Komponente, die Teil des QR-Codesystems in der App ist und den QR-Code für Benutzer anzeigt, übernimmt statisches serverseitiges Rendering (statische SSR) mit erweiterter Navigation. Daher können normale Skripts nicht ausgeführt werden, wenn die Komponente unter erweiterter Navigation geladen oder aktualisiert wird. Zusätzliche Schritte sind erforderlich, um den QR-Code zum Laden der Benutzeroberfläche auszulösen, wenn die Seite geladen wird. Um das Laden des QR-Codes zu erreichen, wird der in ASP.NET Core Blazor JavaScript mit statischem serverseitigem Rendering (static SSR) erläuterte Ansatz übernommen.

Fügen Sie den folgenden JavaScript-Initialisierer zum Ordner des Serverprojekts wwwroot hinzu. Der {NAME} Platzhalter muss der Name der App-Assembly sein, damit Blazor die Datei automatisch sucht und lädt. Wenn der Assemblyname der Server-App BlazorSample lautet, wird die Datei BlazorSample.lib.module.js genannt.

wwwroot/{NAME}.lib.module.js:

const pageScriptInfoBySrc = new Map();

function registerPageScriptElement(src) {
  if (!src) {
    throw new Error('Must provide a non-empty value for the "src" attribute.');
  }

  let pageScriptInfo = pageScriptInfoBySrc.get(src);

  if (pageScriptInfo) {
    pageScriptInfo.referenceCount++;
  } else {
    pageScriptInfo = { referenceCount: 1, module: null };
    pageScriptInfoBySrc.set(src, pageScriptInfo);
    initializePageScriptModule(src, pageScriptInfo);
  }
}

function unregisterPageScriptElement(src) {
  if (!src) {
    return;
  }

  const pageScriptInfo = pageScriptInfoBySrc.get(src);
  
  if (!pageScriptInfo) {
    return;
  }

  pageScriptInfo.referenceCount--;
}

async function initializePageScriptModule(src, pageScriptInfo) {
  if (src.startsWith("./")) {
    src = new URL(src.substr(2), document.baseURI).toString();
  }

  const module = await import(src);

  if (pageScriptInfo.referenceCount <= 0) {
    return;
  }

  pageScriptInfo.module = module;
  module.onLoad?.();
  module.onUpdate?.();
}

function onEnhancedLoad() {
  for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
    if (referenceCount <= 0) {
      module?.onDispose?.();
      pageScriptInfoBySrc.delete(src);
    }
  }

  for (const { module } of pageScriptInfoBySrc.values()) {
    module?.onUpdate?.();
  }
}

export function afterWebStarted(blazor) {
  customElements.define('page-script', class extends HTMLElement {
    static observedAttributes = ['src'];

    attributeChangedCallback(name, oldValue, newValue) {
      if (name !== 'src') {
        return;
      }

      this.src = newValue;
      unregisterPageScriptElement(oldValue);
      registerPageScriptElement(newValue);
    }

    disconnectedCallback() {
      unregisterPageScriptElement(this.src);
    }
  });

  blazor.addEventListener('enhancedload', onEnhancedLoad);
}

Fügen Sie der App die folgende geteilte PageScript Komponente hinzu.

Components/PageScript.razor:

<page-script src="@Src"></page-script>

@code {
    [Parameter]
    [EditorRequired]
    public string Src { get; set; } = default!;
}

Fügen Sie die folgende verbundene JS Datei für die EnableAuthenticator Komponente hinzu, die sich in Components/Account/Pages/Manage/EnableAuthenticator.razor befindet. Die onLoad Funktion erstellt den QR-Code mit Sangmins qrcode.js Bibliothek mithilfe des QR-Code-URI, der von der GenerateQrCodeUri Methode im @code Block der Komponente erstellt wird.

Components/Account/Pages/Manage/EnableAuthenticator.razor.js:

export function onLoad() {
  const uri = document.getElementById('qrCodeData').getAttribute('data-url');
  new QRCode(document.getElementById('qrCode'), uri);
}

Fügen Sie unter der <PageTitle> Komponente in der EnableAuthenticator Komponente die PageScript Komponente mit dem Pfad zur verbundenen JS Datei hinzu:

<PageScript Src="./Components/Account/Pages/Manage/EnableAuthenticator.razor.js" />

Hinweis

Eine Alternative zur Verwendung des Ansatzes mit der PageScript Komponente besteht darin, einen Ereignislistener (blazor.addEventListener("enhancedload", {CALLBACK})) zu verwenden, der in einem afterWebStartedJS Initialisierer registriert ist, um Seitenaktualisierungen zu überwachen, die durch eine erweiterte Navigation verursacht werden. Der Rückruf ({CALLBACK} Platzhalter) führt die QR-Codeinitialisierungslogik aus.

Mit dem Rückrufansatz enhancedload wird der Code für jede erweiterte Navigation ausgeführt, auch wenn der QR-Code <div> nicht gerendert wird. Daher muss zusätzlicher Code hinzugefügt werden, um zu überprüfen, ob der <div> Code vorhanden ist, bevor der Code ausgeführt wird, der einen QR-Code hinzufügt.

Löschen Sie das <div> Element, das die QR-Codeanweisungen enthält:

- <div class="alert alert-info">
-     Learn how to <a href="https://go.microsoft.com/fwlink/?Linkid=852423">enable 
-     QR code generation</a>.
- </div>

Suchen Sie die beiden <div> Elemente, in denen der QR-Code angezeigt werden soll, und wo die QR-Codedaten auf der Seite gespeichert werden.

Nehmen Sie die folgenden Änderungen vor:

  • Geben Sie für das leere <div> dem Element ein id von qrCode.
  • Geben Sie für das <div> mit dem data-url Attribut dem Element ein id von qrCodeData.
- <div></div>
- <div data-url="@authenticatorUri"></div>
+ <div id="qrCode"></div>
+ <div id="qrCodeData" data-url="@authenticatorUri"></div>

Ändern Sie den Websitenamen in der GenerateQrCodeUri Methode der EnableAuthenticator Komponente. Der Standardwert ist Microsoft.AspNetCore.Identity.UI. Ändern Sie den Wert in einen aussagekräftigen Websitenamen, den Benutzer in ihrer Authentifikator-App neben anderen QR-Codes für andere Apps leicht identifizieren können. Lassen Sie die Wert-URL codiert. Entwickler legen in der Regel einen Websitenamen fest, der dem Namen des Unternehmens entspricht. Beispiele: Yahoo, Amazon, Etsy, Microsoft, Zoho.

Im folgenden Beispiel ist der {SITE NAME} Platzhalter der Ort, an dem der Websitename (Firmenname) liegt:

private string GenerateQrCodeUri(string email, string unformattedKey)
{
    return string.Format(
        CultureInfo.InvariantCulture,
        AuthenticatorUriFormat,
-       UrlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"),
+       UrlEncoder.Encode("{SITE NAME}"),
        UrlEncoder.Encode(email),
        unformattedKey);
}

Führen Sie die App aus, und stellen Sie sicher, dass der QR-Code gescannt werden kann und dass der Code überprüft wird.

EnableAuthenticator Komponente in Referenzquelle

Die EnableAuthenticator Komponente kann in der Referenzquelle geprüft werden:

EnableAuthenticator Komponente in Referenzquelle

Hinweis

Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).

Zusätzliche Ressourcen