1. Hinweis
Mit der Web Authentication API, auch WebAuthn genannt, können Sie Anmeldedaten mit Ursprung auf Basis des öffentlichen Schlüssels erstellen und verwenden, um Nutzer zu authentifizieren.
Die API unterstützt die Verwendung von BLE-, NFC- und USB-Roaming-U2F- oder FIDO2-Authentifizierungs-Tools (auch bekannt als Sicherheitsschlüssel) sowie einer Plattform-Authentifizierung, über die Nutzer sich mit ihren Fingerabdrücken oder Displaysperren authentifizieren können.
In diesem Codelab erstellen Sie eine Website mit einer einfachen erneuten Authentifizierungsfunktion, für die ein Fingerabdrucksensor verwendet wird. Die erneute Authentifizierung schützt Kontodaten, da Nutzer, die sich bereits auf einer Website angemeldet haben, sich nach einer gewissen Zeit wieder anmelden müssen, wenn sie versuchen, wichtige Bereiche der Website einzugeben oder die Website neu aufzurufen.
Vorbereitung
- Grundlegendes Verständnis von WebAuthn
- Grundkenntnisse in Programmieren mit JavaScript
Aufgaben
- Mit einer einfachen Authentifizierungsfunktion, die einen Fingerabdrucksensor nutzt, lässt sich eine Website erstellen
Voraussetzungen
- Eines der folgenden Geräte:
- Ein Android-Gerät, vorzugsweise mit biometrischem Sensor
- Ein iPhone oder iPad mit Touch ID oder Face ID unter iOS 14 oder höher
- MacBook Pro oder Air mit Touch ID unter macOS Big Sur oder höher
- Windows 10 19H1 oder höher mit der Einrichtung von Windows Hello
- Einer der folgenden Browser:
- Google Chrome 67 oder höher
- Microsoft Edge 85 oder höher
- Safari 14 oder höher
2. Einrichten
In diesem Codelab nutzen Sie einen Dienst namens glitch. Hier können Sie clientseitigen und serverseitigen Code mit JavaScript bearbeiten und sofort bereitstellen.
Rufen Sie https://glitch.com/editaggregate/webauthn-codelab-start auf.
So funktionierts
Gehen Sie so vor, um den Anfangsstatus der Website zu sehen:
- Klicken Sie auf Einblenden & ; In einem neuen Fenster, um die Live-Website aufzurufen.
- Geben Sie einen beliebigen Nutzernamen ein und klicken Sie auf Weiter.
- Geben Sie ein Passwort ein und klicken Sie auf Anmelden.
Das Passwort wird ignoriert, du bist aber weiterhin authentifiziert. Sie gelangen auf die Startseite.
- Klicken Sie auf Wiederholen und wiederholen Sie den zweiten, dritten und vierten Schritt.
- Wähle Abmelden aus.
Beachten Sie, dass Sie das Passwort jedes Mal eingeben müssen, wenn Sie sich anmelden. Sie emuliert einen Nutzer, der sich erneut authentifizieren muss, bevor er auf einen wichtigen Bereich einer Website zugreifen kann.
Code remixen
- Rufen Sie WebAuthn / FIDO2 API Codelab auf.
- Klicken Sie auf den Namen Ihres Projekts. Tippen Sie auf Projekt remixen, um das Projekt zu verzweigen, und fahren Sie mit der eigenen Version unter einer neuen URL fort.
3. Anmeldedaten mit einem Fingerabdruck registrieren
Sie müssen die von einem UVPA generierten Anmeldedaten in das Gerät einbauen und die Identität des Nutzers bestätigen. Je nach Gerät des Nutzers wird dieser Schalter in der Regel als Fingerabdrucksensor angesehen.
Sie fügen diese Funktion auf der Seite /home
hinzu:
Funktion registerCredential()
erstellen
Erstellt eine registerCredential()
-Funktion, mit der neue Anmeldedaten registriert werden.
public/client.js
export const registerCredential = async () => {
};
Identitätsbestätigung und andere Optionen vom Serverendpunkt abrufen
Bevor Sie den Nutzer bitten, neue Anmeldedaten zu registrieren, bitten Sie ihn, die Parameter zurückzugeben, die WebAuthn, einschließlich einer Identitätsbestätigung, übergeben. Glücklicherweise haben Sie bereits einen Serverendpunkt, der mit solchen Parametern antwortet.
Fügen Sie registerCredential()
den folgenden Code hinzu.
public/client.js
const opts = {
attestation: 'none',
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required',
requireResidentKey: false
}
};
const options = await _fetch('/auth/registerRequest', opts);
Das Protokoll zwischen einem Server und einem Client ist nicht Teil der WebAuthn-Spezifikation. Dieses Codelab ist jedoch auf die WebAuthn-Spezifikation und das JSON-Objekt ausgerichtet, das du an den Server übergibst, damit PublicKeyCredentialCreationOptions
für dich intuitiv funktioniert. In der folgenden Tabelle sind die wichtigen Parameter aufgeführt, die Sie an den Server übergeben können:
Parameter | Textzeilen | ||
| Einstellung für die Attestierungsübertragung – | ||
| Array von | ||
|
| Filtern Sie die verfügbaren Authenticators. Wenn Sie eine Authentifizierung an das Gerät vornehmen möchten, verwenden Sie „ | |
| Legen Sie fest, ob die lokale Nutzerbestätigung für die Authentifizierung und die | ||
| Verwenden Sie |
Weitere Informationen zu diesen Optionen finden Sie unter 5.4. Optionen für die Erstellung von Anmeldedaten (Wörterbuch PublicKeyCredentialCreationOptions
)
Die folgenden Beispieloptionen erhalten Sie vom Server.
{
"rp": {
"name": "WebAuthn Codelab",
"id": "webauthn-codelab.glitch.me"
},
"user": {
"displayName": "User Name",
"id": "...",
"name": "test"
},
"challenge": "...",
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}, {
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [
{
"id": "...",
"type": "public-key",
"transports": [
"internal"
]
}
],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"userVerification": "required"
}
}
Anmeldedaten erstellen
- Da diese Optionen codiert sind, um das HTTP-Protokoll zu verwenden, konvertieren Sie einige Parameter zurück in das Binärprogramm, insbesondere
user.id
,challenge
und Instanzen vonid
imexcludeCredentials
-Array:
public/client.js
options.user.id = base64url.decode(options.user.id);
options.challenge = base64url.decode(options.challenge);
if (options.excludeCredentials) {
for (let cred of options.excludeCredentials) {
cred.id = base64url.decode(cred.id);
}
}
- Rufen Sie die Methode
navigator.credentials.create()
auf, um neue Anmeldedaten zu erstellen.
Bei diesem Aufruf interagiert der Browser mit dem Authenticator und versucht, die Identität des Nutzers mit der UVPA zu bestätigen.
public/client.js
const cred = await navigator.credentials.create({
publicKey: options,
});
Sobald der Nutzer seine Identität bestätigt hat, sollten Sie ein Berechtigungsobjekt erhalten, das Sie an den Server senden und den Authenticator authentifizieren können.
Anmeldedaten am Serverendpunkt registrieren
Hier ist ein Beispiel für ein Berechtigungsobjekt, das Sie erhalten haben sollten.
{
"id": "...",
"rawId": "...",
"type": "public-key",
"response": {
"clientDataJSON": "...",
"attestationObject": "..."
}
}
- Wenn Sie ein Optionsobjekt zum Registrieren von Anmeldedaten erhalten haben, codieren Sie die binären Parameter der Anmeldedaten so, dass sie als String an den Server übertragen werden können:
public/client.js
const credential = {};
credential.id = cred.id;
credential.rawId = base64url.encode(cred.rawId);
credential.type = cred.type;
if (cred.response) {
const clientDataJSON =
base64url.encode(cred.response.clientDataJSON);
const attestationObject =
base64url.encode(cred.response.attestationObject);
credential.response = {
clientDataJSON,
attestationObject,
};
}
- Speichern Sie die Anmeldedaten lokal, damit Sie sie zur Authentifizierung verwenden können, wenn der Nutzer zurückkehrt.
public/client.js
localStorage.setItem(`credId`, credential.id);
- Senden Sie das Objekt an den Server. Wenn
HTTP code 200
zurückgegeben wird, prüfen Sie die neuen Anmeldedaten als erfolgreich.
public/client.js
return await _fetch('/auth/registerResponse' , credential);
Sie haben jetzt die vollständige Funktion registerCredential()
.
Endgültiger Code für diesen Abschnitt
public/client.js
...
export const registerCredential = async () => {
const opts = {
attestation: 'none',
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required',
requireResidentKey: false
}
};
const options = await _fetch('/auth/registerRequest', opts);
options.user.id = base64url.decode(options.user.id);
options.challenge = base64url.decode(options.challenge);
if (options.excludeCredentials) {
for (let cred of options.excludeCredentials) {
cred.id = base64url.decode(cred.id);
}
}
const cred = await navigator.credentials.create({
publicKey: options
});
const credential = {};
credential.id = cred.id;
credential.rawId = base64url.encode(cred.rawId);
credential.type = cred.type;
if (cred.response) {
const clientDataJSON =
base64url.encode(cred.response.clientDataJSON);
const attestationObject =
base64url.encode(cred.response.attestationObject);
credential.response = {
clientDataJSON,
attestationObject
};
}
localStorage.setItem(`credId`, credential.id);
return await _fetch('/auth/registerResponse' , credential);
};
...
4. UI erstellen, um Anmeldedaten zu registrieren, abzurufen und zu entfernen
Eine Liste der registrierten Anmeldedaten und Schaltflächen können Sie löschen.
UI-Platzhalter erstellen
UI zum Auflisten von Anmeldedaten und eine Schaltfläche zum Registrieren neuer Anmeldedaten hinzufügen. Je nachdem, ob die Funktion verfügbar ist oder nicht, entfernen Sie die hidden
-Klasse entweder aus der Warnmeldung oder von der Schaltfläche, um neue Anmeldedaten zu registrieren. ul#list
ist der Platzhalter zum Hinzufügen einer Liste registrierter Anmeldedaten.
views/home.html
<p id="uvpa_unavailable" class="hidden">
This device does not support User Verifying Platform Authenticator. You can't register a credential.
</p>
<h3 class="mdc-typography mdc-typography--headline6">
Your registered credentials:
</h3>
<section>
<div id="list"></div>
</section>
<mwc-button id="register" class="hidden" icon="fingerprint" raised>Add a credential</mwc-button>
Funktionserkennung und UVPA-Verfügbarkeit
Gehen Sie so vor, um die UVPA-Verfügbarkeit zu prüfen:
- Prüfen Sie
window.PublicKeyCredential
, um zu prüfen, ob WebAuthn verfügbar ist. - Rufe
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
auf, um zu prüfen, ob ein UVPA verfügbar ist . Wenn sie verfügbar sind, wird die Schaltfläche zum Registrieren neuer Anmeldedaten angezeigt. Ist keines von beidem verfügbar, wird die Warnmeldung angezeigt.
views/home.html
const register = document.querySelector('#register');
if (window.PublicKeyCredential) {
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
.then(uvpaa => {
if (uvpaa) {
register.classList.remove('hidden');
} else {
document
.querySelector('#uvpa_unavailable')
.classList.remove('hidden');
}
});
} else {
document
.querySelector('#uvpa_unavailable')
.classList.remove('hidden');
}
Liste mit Anmeldedaten abrufen und anzeigen
- Erstellen Sie eine
getCredentials()
-Funktion, um registrierte Anmeldedaten abzurufen und in einer Liste anzeigen zu lassen. Glücklicherweise haben Sie auf dem Server/auth/getKeys
bereits einen praktischen Endpunkt, von dem Sie registrierte Anmeldedaten für den angemeldeten Nutzer abrufen können.
Der zurückgegebene JSON-Code enthält Informationen wie Anmeldedaten wie id
und publicKey
. Sie können HTML-Code erstellen, der den Nutzern präsentiert wird.
views/home.html
const getCredentials = async () => {
const res = await _fetch('/auth/getKeys');
const list = document.querySelector('#list');
const creds = html`${res.credentials.length > 0 ? res.credentials.map(cred => html`
<div class="mdc-card credential">
<span class="mdc-typography mdc-typography--body2">${cred.credId}</span>
<pre class="public-key">${cred.publicKey}</pre>
<div class="mdc-card__actions">
<mwc-button id="${cred.credId}" @click="${removeCredential}" raised>Remove</mwc-button>
</div>
</div>`) : html`
<p>No credentials found.</p>
`}`;
render(creds, list);
};
- Rufen Sie
getCredentials()
auf, um verfügbare Anmeldedaten anzuzeigen, sobald der Nutzer auf die Seite/home
gelangt.
views/home.html
getCredentials();
Anmeldedaten entfernen
In der Liste der Anmeldedaten haben Sie eine Schaltfläche hinzugefügt, über die Sie die einzelnen Anmeldedaten entfernen können. Sie können eine Anfrage zusammen mit dem Suchparameter credId
an /auth/removeKey
senden, um sie zu entfernen.
public/client.js
export const unregisterCredential = async (credId) => {
localStorage.removeItem('credId');
return _fetch(`/auth/removeKey?credId=${encodeURIComponent(credId)}`);
};
- Hänge
unregisterCredential
an die vorhandeneimport
-Anweisung an.
views/home.html
import { _fetch, unregisterCredential } from '/client.js';
- Fügen Sie eine Funktion hinzu, die aufgerufen wird, wenn der Nutzer auf Entfernen klickt.
views/home.html
const removeCredential = async e => {
try {
await unregisterCredential(e.target.id);
getCredentials();
} catch (e) {
alert(e);
}
};
Anmeldedaten registrieren
Sie können registerCredential()
aufrufen, um neue Anmeldedaten zu registrieren, wenn der Nutzer auf Anmeldedaten hinzufügen klickt.
- Hänge
registerCredential
an die vorhandeneimport
-Anweisung an.
views/home.html
import { _fetch, registerCredential, unregisterCredential } from '/client.js';
- Rufen Sie
registerCredential()
mit Optionen fürnavigator.credentials.create()
auf.
Vergiss nicht, die Liste der Anmeldedaten zu verlängern, indem du nach der Registrierung getCredentials()
aufrufst.
views/home.html
register.addEventListener('click', e => {
registerCredential().then(user => {
getCredentials();
}).catch(e => alert(e));
});
Sie sollten jetzt in der Lage sein, neue Anmeldedaten zu registrieren und Informationen dazu anzeigen zu lassen. Probieren Sie es auf Ihrer Website aus.
Endgültiger Code für diesen Abschnitt
views/home.html
...
<p id="uvpa_unavailable" class="hidden">
This device does not support User Verifying Platform Authenticator. You can't register a credential.
</p>
<h3 class="mdc-typography mdc-typography--headline6">
Your registered credentials:
</h3>
<section>
<div id="list"></div>
<mwc-fab id="register" class="hidden" icon="add"></mwc-fab>
</section>
<mwc-button raised><a href="/reauth">Try reauth</a></mwc-button>
<mwc-button><a href="/auth/signout">Sign out</a></mwc-button>
</main>
<script type="module">
import { _fetch, registerCredential, unregisterCredential } from '/client.js';
import { html, render } from 'https://unpkg.com/lit-html@1.0.0/lit-html.js?module';
const register = document.querySelector('#register');
if (window.PublicKeyCredential) {
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
.then(uvpaa => {
if (uvpaa) {
register.classList.remove('hidden');
} else {
document
.querySelector('#uvpa_unavailable')
.classList.remove('hidden');
}
});
} else {
document
.querySelector('#uvpa_unavailable')
.classList.remove('hidden');
}
const getCredentials = async () => {
const res = await _fetch('/auth/getKeys');
const list = document.querySelector('#list');
const creds = html`${res.credentials.length > 0 ? res.credentials.map(cred => html`
<div class="mdc-card credential">
<span class="mdc-typography mdc-typography--body2">${cred.credId}</span>
<pre class="public-key">${cred.publicKey}</pre>
<div class="mdc-card__actions">
<mwc-button id="${cred.credId}" @click="${removeCredential}" raised>Remove</mwc-button>
</div>
</div>`) : html`
<p>No credentials found.</p>
`}`;
render(creds, list);
};
getCredentials();
const removeCredential = async e => {
try {
await unregisterCredential(e.target.id);
getCredentials();
} catch (e) {
alert(e);
}
};
register.addEventListener('click', e => {
registerCredential({
attestation: 'none',
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required',
requireResidentKey: false
}
})
.then(user => {
getCredentials();
})
.catch(e => alert(e));
});
</script>
...
public/client.js
...
export const unregisterCredential = async (credId) => {
localStorage.removeItem('credId');
return _fetch(`/auth/removeKey?credId=${encodeURIComponent(credId)}`);
};
...
5. Nutzer mit einem Fingerabdruck authentifizieren
Sie verfügen jetzt über Anmeldedaten, die für die Authentifizierung des Nutzers verwendet werden können. Jetzt fügen Sie der Website eine neue Authentifizierungsfunktion hinzu. Für Nutzer:
Wenn der Nutzer auf die Seite /reauth
gelangt, wird die Schaltfläche Authentifizieren angezeigt, wenn die biometrische Authentifizierung möglich ist. Die Authentifizierung mit einem Fingerabdruck (UVPA) beginnt, wenn sie auf Authentifizieren tippen, sich erfolgreich authentifizieren und dann zur Seite /home
gelangen. Wenn keine biometrische Authentifizierung verfügbar ist oder eine Authentifizierung mit biometrischen Daten fehlschlägt, wird die vorhandene UI verwendet, um das vorhandene Passwortformular zu verwenden.
Funktion authenticate()
erstellen
Erstellen Sie eine Funktion namens „authenticate()
“, die die Identität des Nutzers mit einem Fingerabdruck verifiziert. Hier fügen Sie JavaScript-Code hinzu:
public/client.js
export const authenticate = async () => {
};
Identitätsbestätigung und andere Optionen vom Serverendpunkt abrufen
- Prüfen Sie vor der Authentifizierung, ob der Nutzer eine Anmeldedaten-ID hat, und legen Sie sie als Suchparameter fest, wenn er dies tut.
Wenn Sie zusammen mit anderen Optionen eine Anmeldedaten-ID angeben, kann der Server die entsprechende allowCredentials
bereitstellen. Dies macht die Bestätigung der Nutzer zuverlässig.
public/client.js
const opts = {};
let url = '/auth/signinRequest';
const credId = localStorage.getItem(`credId`);
if (credId) {
url += `?credId=${encodeURIComponent(credId)}`;
}
- Bevor Sie den Nutzer zur Authentifizierung auffordern, sollte er eine Aufforderung zur Identitätsbestätigung und andere Parameter senden. Rufen Sie
_fetch()
mitopts
als Argument auf, um eine POST-Anfrage an den Server zu senden.
public/client.js
const options = await _fetch(url, opts);
Im Folgenden finden Sie einige Beispieloptionen, die Sie erhalten sollten (stimmt mit PublicKeyCredentialRequestOptions
überein).
{
"challenge": "...",
"timeout": 1800000,
"rpId": "webauthn-codelab.glitch.me",
"userVerification": "required",
"allowCredentials": [
{
"id": "...",
"type": "public-key",
"transports": [
"internal"
]
}
]
}
Die wichtigste Option ist hier allowCredentials
. Wenn Sie Optionen vom Server erhalten, sollte allowCredentials
entweder ein einzelnes Objekt in einem Array oder ein leeres Array sein, je nachdem, ob auf dem Server eine Anmeldedaten mit der ID im Suchparameter gefunden wird.
- Lösen Sie das Versprechen mit
null
, wennallowCredentials
ein leeres Array ist, sodass die UI wieder nach einem Passwort fragt.
if (options.allowCredentials.length === 0) {
console.info('No registered credentials found.');
return Promise.resolve(null);
}
Nutzer lokal bestätigen und Anmeldedaten erhalten
- Da diese Optionen codiert sind, um das HTTP-Protokoll zu verwenden, konvertieren Sie einige Parameter zurück in das Binärprogramm, insbesondere
challenge
und Instanzen vonid
imallowCredentials
-Array:
public/client.js
options.challenge = base64url.decode(options.challenge);
for (let cred of options.allowCredentials) {
cred.id = base64url.decode(cred.id);
}
- Rufen Sie die
navigator.credentials.get()
-Methode auf, um die Identität des Nutzers mit einem UVPA zu bestätigen.
public/client.js
const cred = await navigator.credentials.get({
publicKey: options
});
Sobald der Nutzer seine Identität bestätigt hat, sollten Sie ein Anmeldeobjekt erhalten, das Sie an den Server senden und den Nutzer authentifizieren können.
Anmeldedaten überprüfen
Hier sehen Sie ein Beispiel für ein PublicKeyCredential
-Objekt (response
ist AuthenticatorAssertionResponse
), das Sie erhalten haben sollten:
{
"id": "...",
"type": "public-key",
"rawId": "...",
"response": {
"clientDataJSON": "...",
"authenticatorData": "...",
"signature": "...",
"userHandle": ""
}
}
- Codiere die binären Parameter der Anmeldedaten, damit sie als String an den Server gesendet werden können:
public/client.js
const credential = {};
credential.id = cred.id;
credential.type = cred.type;
credential.rawId = base64url.encode(cred.rawId);
if (cred.response) {
const clientDataJSON =
base64url.encode(cred.response.clientDataJSON);
const authenticatorData =
base64url.encode(cred.response.authenticatorData);
const signature =
base64url.encode(cred.response.signature);
const userHandle =
base64url.encode(cred.response.userHandle);
credential.response = {
clientDataJSON,
authenticatorData,
signature,
userHandle,
};
}
- Senden Sie das Objekt an den Server. Wenn
HTTP code 200
zurückgegeben wird, prüfen Sie den Nutzer als erfolgreich angemeldet:
public/client.js
return await _fetch(`/auth/signinResponse`, credential);
Sie haben jetzt die vollständige Funktion authentication()
.
Endgültiger Code für diesen Abschnitt
public/client.js
...
export const authenticate = async () => {
const opts = {};
let url = '/auth/signinRequest';
const credId = localStorage.getItem(`credId`);
if (credId) {
url += `?credId=${encodeURIComponent(credId)}`;
}
const options = await _fetch(url, opts);
if (options.allowCredentials.length === 0) {
console.info('No registered credentials found.');
return Promise.resolve(null);
}
options.challenge = base64url.decode(options.challenge);
for (let cred of options.allowCredentials) {
cred.id = base64url.decode(cred.id);
}
const cred = await navigator.credentials.get({
publicKey: options
});
const credential = {};
credential.id = cred.id;
credential.type = cred.type;
credential.rawId = base64url.encode(cred.rawId);
if (cred.response) {
const clientDataJSON =
base64url.encode(cred.response.clientDataJSON);
const authenticatorData =
base64url.encode(cred.response.authenticatorData);
const signature =
base64url.encode(cred.response.signature);
const userHandle =
base64url.encode(cred.response.userHandle);
credential.response = {
clientDataJSON,
authenticatorData,
signature,
userHandle,
};
}
return await _fetch(`/auth/signinResponse`, credential);
};
...
6. Erneute Authentifizierung aktivieren
Build-UI
Wenn der Nutzer zurückkehrt, sollte er sich einfach und sicher erneut authentifizieren. Hier kommt die biometrische Authentifizierung ins Spiel. Es gibt jedoch Fälle, in denen die biometrische Authentifizierung nicht funktioniert:
- Die UVPA ist nicht verfügbar.
- Der Nutzer hat noch keine Anmeldedaten auf seinem Gerät registriert.
- Der Speicherinhalt wird gelöscht und das Gerät speichert die Anmeldedaten-ID nicht mehr.
- Der Nutzer kann seine Identität nicht bestätigen, z. B. weil er nass ist oder er eine Maske trägt.
Aus diesem Grund solltest du immer andere Anmeldeoptionen als Fallbacks angeben. In diesem Codelab nutzen Sie eine formularbasierte Passwortlösung.
- UI hinzufügen, um eine Authentifizierungsschaltfläche einzublenden, mit der die biometrische Authentifizierung zusätzlich zum Passwortformular aufgerufen wird.
Mit der Klasse hidden
kannst du eine davon nach Bedarf ein- und ausblenden.
views/reauth.html (in englischer Sprache)
<div id="uvpa_available" class="hidden">
<h2>
Verify your identity
</h2>
<div>
<mwc-button id="reauth" raised>Authenticate</mwc-button>
</div>
<div>
<mwc-button id="cancel">Sign-in with password</mwc-button>
</div>
</div>
- Hängen Sie
class="hidden"
an das Formular an:
views/reauth.html (in englischer Sprache)
<form id="form" method="POST" action="/auth/password" class="hidden">
Funktionserkennung und UVPA-Verfügbarkeit
Nutzer müssen sich mit einem Passwort anmelden, wenn eine der folgenden Bedingungen erfüllt ist:
- WebAuthn ist nicht verfügbar.
- UVPA ist nicht verfügbar.
- Die Anmeldedaten-ID für diese UVPA ist nicht sichtbar.
Lassen Sie die Schaltfläche für die Authentifizierung selektiv anzeigen oder ausblenden:
views/reauth.html (in englischer Sprache)
if (window.PublicKeyCredential) {
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
.then(uvpaa => {
if (uvpaa && localStorage.getItem(`credId`)) {
document
.querySelector('#uvpa_available')
.classList.remove('hidden');
} else {
form.classList.remove('hidden');
}
});
} else {
form.classList.remove('hidden');
}
Fallback auf Passwortformular
Der Nutzer sollte auch die Möglichkeit haben, sich mit einem Passwort anzumelden.
Passwortformular anzeigen und Authentifizierungsschaltfläche ausblenden, wenn der Nutzer auf Mit Passwort anmelden klickt:
views/reauth.html (in englischer Sprache)
const cancel = document.querySelector('#cancel');
cancel.addEventListener('click', e => {
form.classList.remove('hidden');
document
.querySelector('#uvpa_available')
.classList.add('hidden');
});
Biometrische Authentifizierung aufrufen
Abschließend aktivieren Sie die biometrische Authentifizierung.
- Hänge
authenticate
an die vorhandeneimport
-Anweisung an:
views/reauth.html (in englischer Sprache)
import { _fetch, authenticate } from '/client.js';
- Rufe
authenticate()
auf, wenn der Nutzer auf Authentifizieren tippt, um die biometrische Authentifizierung zu starten.
Prüfen Sie, ob bei der biometrischen Authentifizierung ein Fehler auf das Passwortformular zurückgeht.
views/reauth.html (in englischer Sprache)
const button = document.querySelector('#reauth');
button.addEventListener('click', e => {
authenticate().then(user => {
if (user) {
location.href = '/home';
} else {
throw 'User not found.';
}
}).catch(e => {
console.error(e.message || e);
alert('Authentication failed. Use password to sign-in.');
form.classList.remove('hidden');
document.querySelector('#uvpa_available').classList.add('hidden');
});
});
Endgültiger Code für diesen Abschnitt
views/reauth.html (in englischer Sprache)
...
<main class="content">
<div id="uvpa_available" class="hidden">
<h2>
Verify your identity
</h2>
<div>
<mwc-button id="reauth" raised>Authenticate</mwc-button>
</div>
<div>
<mwc-button id="cancel">Sign-in with password</mwc-button>
</div>
</div>
<form id="form" method="POST" action="/auth/password" class="hidden">
<h2>
Enter a password
</h2>
<input type="hidden" name="username" value="{{username}}" />
<div class="mdc-text-field mdc-text-field--filled">
<span class="mdc-text-field__ripple"></span>
<label class="mdc-floating-label" id="password-label">password</label>
<input type="password" class="mdc-text-field__input" aria-labelledby="password-label" name="password" />
<span class="mdc-line-ripple"></span>
</div>
<input type="submit" class="mdc-button mdc-button--raised" value="Sign-In" />
<p class="instructions">password will be ignored in this demo.</p>
</form>
</main>
<script src="https://unpkg.com/material-components-web@7.0.0/dist/material-components-web.min.js"></script>
<script type="module">
new mdc.textField.MDCTextField(document.querySelector('.mdc-text-field'));
import { _fetch, authenticate } from '/client.js';
const form = document.querySelector('#form');
form.addEventListener('submit', e => {
e.preventDefault();
const form = new FormData(e.target);
const cred = {};
form.forEach((v, k) => cred[k] = v);
_fetch(e.target.action, cred)
.then(user => {
location.href = '/home';
})
.catch(e => alert(e));
});
if (window.PublicKeyCredential) {
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
.then(uvpaa => {
if (uvpaa && localStorage.getItem(`credId`)) {
document
.querySelector('#uvpa_available')
.classList.remove('hidden');
} else {
form.classList.remove('hidden');
}
});
} else {
form.classList.remove('hidden');
}
const cancel = document.querySelector('#cancel');
cancel.addEventListener('click', e => {
form.classList.remove('hidden');
document
.querySelector('#uvpa_available')
.classList.add('hidden');
});
const button = document.querySelector('#reauth');
button.addEventListener('click', e => {
authenticate().then(user => {
if (user) {
location.href = '/home';
} else {
throw 'User not found.';
}
}).catch(e => {
console.error(e.message || e);
alert('Authentication failed. Use password to sign-in.');
form.classList.remove('hidden');
document.querySelector('#uvpa_available').classList.add('hidden');
});
});
</script>
...
7. Glückwunsch!
Du hast dieses Codelab abgeschlossen.
Weitere Informationen
- Web Authentication: Eine API für den Zugriff auf die Anmeldedaten für einen öffentlichen Schlüssel (Stufe 1)
- Einführung in die WebAuthn API
- FIDO WebAuthn-Workshop
- WebAuthn-Leitfaden: DUOSEC
- Ihre erste FIDO2 API für Android
Wir möchten uns bei Yuriy Ackermann von der FIDO Alliance bedanken.