1. Sebelum memulai
Web Authentication API, yang juga dikenal sebagai WebAuthn, memungkinkan Anda membuat dan menggunakan kredensial kunci publik dengan cakupan asal untuk mengautentikasi pengguna.
API tersebut mendukung penggunaan pengautentikasi BLE, NFC, dan U2F atau FIDO2 roaming USB (yang juga disebut kunci keamanan) serta pengautentikasi platform, yang memungkinkan pengguna mengautentikasi dengan sidik jari atau kunci layar mereka.
Dalam codelab ini, Anda akan mem-build situs dengan fungsi autentikasi ulang sederhana yang menggunakan sensor sidik jari. Autentikasi ulang melindungi data akun karena mewajibkan pengguna yang sudah login ke situs untuk melakukan autentikasi ulang saat mereka mencoba memasuki bagian penting situs atau mengunjungi kembali situs setelah jangka waktu tertentu.
Prasyarat
- Pemahaman dasar tentang cara kerja WebAuthn
- Keterampilan pemrograman dasar dengan JavaScript
Yang akan Anda lakukan
- Mem-build situs dengan fungsi autentikasi ulang sederhana yang menggunakan sensor sidik jari
Yang akan Anda perlukan
- Salah satu perangkat berikut:
- Perangkat Android, sebaiknya dengan sensor biometrik
- iPhone atau iPad dengan Touch ID atau Face ID pada iOS 14 atau lebih tinggi
- MacBook Pro atau Air dengan Touch ID di macOS Big Sur atau yang lebih tinggi
- Windows 10 19H1 atau yang lebih tinggi dengan penyiapan Windows Hello
- Salah satu browser berikut:
- Google Chrome 67 atau yang lebih tinggi
- Microsoft Edge 85 atau yang lebih tinggi
- Safari 14 atau yang lebih tinggi
2. Memulai persiapan
Dalam codelab ini, Anda akan menggunakan layanan yang disebut glitch. Di sinilah Anda dapat mengedit kode sisi server dan klien dengan JavaScript, dan langsung men-deploynya.
Buka https://glitch.com/edit/#!/webauthn-codelab-start.
Lihat cara kerjanya
Ikuti langkah-langkah berikut untuk melihat status awal situs:
- Klik Show > In a New Window untuk melihat situs aktif.
- Masukkan nama pengguna pilihan Anda, lalu klik Next.
- Masukkan sandi dan klik Sign-in.
Sandi diabaikan, tetapi Anda masih terautentikasi. Anda akan diarahkan ke halaman beranda.
- Klik Try reauth, dan ulangi langkah kedua, ketiga, dan keempat.
- Klik Sign out.
Perhatikan bahwa Anda harus memasukkan sandi setiap kali Anda mencoba login. Tindakan ini mengemulasikan pengguna yang perlu melakukan autentikasi ulang sebelum mereka dapat mengakses bagian penting pada situs.
Melakukan remix kode
- Buka Codelab WebAuthn / FIDO2 API.
- Klik nama project Anda > Remix Project untuk melakukan fork project dan melanjutkan dengan versi Anda sendiri di URL baru.
3. Mendaftarkan kredensial dengan sidik jari
Anda harus mendaftarkan kredensial yang dihasilkan oleh UVPA, pengautentikasi yang terintegrasi di dalam perangkat dan memverifikasi identitas pengguna. Ini biasanya dianggap sebagai sensor sidik jari, bergantung pada perangkat pengguna.
Tambahkan fitur ini ke halaman /home
:
Membuat fungsi registerCredential()
Buat fungsi registerCredential()
, yang mendaftarkan kredensial baru.
public/client.js
export const registerCredential = async () => {
};
Mendapatkan verifikasi login dan opsi lainnya dari endpoint server
Sebelum meminta pengguna untuk mendaftarkan kredensial baru, minta server agar menampilkan parameter untuk meneruskan WebAuthn, termasuk verifikasi login. Untungnya, Anda sudah memiliki endpoint server yang merespons dengan parameter tersebut.
Tambahkan kode berikut ke registerCredential()
.
public/client.js
const opts = {
attestation: 'none',
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required',
requireResidentKey: false
}
};
const options = await _fetch('/auth/registerRequest', opts);
Protokol antara server dan klien bukan bagian dari spesifikasi WebAuthn. Namun, codelab ini dirancang agar sesuai dengan spesifikasi WebAuthn, dan objek JSON yang Anda teruskan ke server sangat mirip dengan PublicKeyCredentialCreationOptions
sehingga ini intuitif bagi Anda. Tabel berikut berisi parameter penting yang dapat Anda teruskan ke server dan menjelaskan tindakan yang dilakukan parameter:
Parameter | Deskripsi | ||
| Preferensi untuk pernyataan pengesahan— | ||
| Array | ||
|
| Filter pengautentikasi yang tersedia. Jika Anda ingin pengautentikasi terhubung ke perangkat, gunakan " | |
| Tentukan apakah verifikasi pengguna lokal pengautentikasi adalah " | ||
| Gunakan |
Untuk mempelajari opsi ini lebih lanjut, lihat 5.4. Opsi untuk Pembuatan Kredensial (kamus PublicKeyCredentialCreationOptions
).
Berikut adalah opsi contoh yang Anda terima dari 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"
}
}
Membuat kredensial
- Karena opsi ini dikirimkan dan dienkode untuk melalui protokol HTTP, konversikan beberapa parameter kembali ke biner, khususnya,
user.id
,challenge
, dan instanceid
yang disertakan dalam arrayexcludeCredentials
:
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);
}
}
- Panggil metode
navigator.credentials.create()
untuk membuat kredensial baru.
Dengan panggilan ini, browser berinteraksi dengan pengautentikasi dan mencoba memverifikasi identitas pengguna dengan UVPA.
public/client.js
const cred = await navigator.credentials.create({
publicKey: options,
});
Setelah pengguna memverifikasi identitasnya, Anda akan menerima objek kredensial yang dapat dikirim ke server dan mendaftarkan pengautentikasi.
Mendaftarkan kredensial ke endpoint server
Berikut adalah contoh objek kredensial yang seharusnya Anda terima.
{
"id": "...",
"rawId": "...",
"type": "public-key",
"response": {
"clientDataJSON": "...",
"attestationObject": "..."
}
}
- Seperti saat Anda menerima objek opsi untuk mendaftarkan kredensial, enkode parameter biner kredensial sehingga dapat dikirim ke server sebagai string:
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,
};
}
- Simpan ID kredensial secara lokal sehingga Anda dapat menggunakannya untuk autentikasi saat pengguna kembali:
public/client.js
localStorage.setItem(`credId`, credential.id);
- Kirim objek ke server dan, jika objek menampilkan
HTTP code 200
, pertimbangkan bahwa kredensial baru tersebut berhasil didaftarkan.
public/client.js
return await _fetch('/auth/registerResponse' , credential);
Anda sekarang memiliki fungsi registerCredential()
yang lengkap.
Kode akhir untuk bagian ini
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. Mem-build UI untuk mendaftarkan, mendapatkan, dan menghapus kredensial
Akan sangat menyenangkan jika Anda memiliki daftar kredensial terdaftar dan tombol untuk menghapusnya.
Mem-build placeholder UI
Tambahkan UI untuk mencantumkan kredensial dan tombol untuk mendaftarkan kredensial baru. Bergantung pada apakah fitur ini tersedia atau tidak, hapus class hidden
dari pesan peringatan atau tombol untuk mendaftarkan kredensial baru. ul#list
adalah placeholder untuk menambahkan daftar kredensial terdaftar.
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>
Deteksi fitur dan ketersediaan UVPA
Ikuti langkah-langkah berikut untuk memeriksa ketersediaan UVPA:
- Cermati
window.PublicKeyCredential
untuk memeriksa apakah WebAuthn tersedia. - Panggil
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
untuk memeriksa apakah UVPA tersedia. Jika tersedia, tampilkan tombol untuk mendaftarkan kredensial baru. Jika salah satunya tidak tersedia, tampilkan pesan peringatan.
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');
}
Mendapatkan dan menampilkan daftar kredensial
- Buat fungsi
getCredentials()
agar Anda bisa mendapatkan kredensial terdaftar dan menampilkannya di daftar. Untungnya, Anda sudah memiliki endpoint praktis di/auth/getKeys
server tempat Anda dapat mengambil kredensial yang terdaftar untuk pengguna yang login.
JSON yang ditampilkan menyertakan informasi kredensial, seperti id
dan publicKey
. Anda dapat mem-build HTML untuk menampilkannya kepada pengguna.
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);
};
- Panggil
getCredentials()
untuk menampilkan kredensial yang tersedia segera setelah pengguna membuka halaman/home
.
views/home.html
getCredentials();
Menghapus kredensial
Dalam daftar kredensial, Anda menambahkan tombol untuk menghapus setiap kredensial. Anda dapat mengirim permintaan ke /auth/removeKey
beserta parameter kueri credId
untuk menghapusnya.
public/client.js
export const unregisterCredential = async (credId) => {
localStorage.removeItem('credId');
return _fetch(`/auth/removeKey?credId=${encodeURIComponent(credId)}`);
};
- Tambahkan
unregisterCredential
ke pernyataanimport
yang ada.
views/home.html
import { _fetch, unregisterCredential } from '/client.js';
- Tambahkan fungsi yang akan dipanggil saat pengguna mengklik Remove.
views/home.html
const removeCredential = async e => {
try {
await unregisterCredential(e.target.id);
getCredentials();
} catch (e) {
alert(e);
}
};
Mendaftarkan kredensial
Anda dapat memanggil registerCredential()
untuk mendaftarkan kredensial baru saat pengguna mengklik Add a credential.
- Tambahkan
registerCredential
ke pernyataanimport
yang ada.
views/home.html
import { _fetch, registerCredential, unregisterCredential } from '/client.js';
- Panggil
registerCredential()
dengan opsi untuknavigator.credentials.create()
.
Jangan lupa untuk memperbarui daftar kredensial dengan memanggil getCredentials()
setelah pendaftaran.
views/home.html
register.addEventListener('click', e => {
registerCredential().then(user => {
getCredentials();
}).catch(e => alert(e));
});
Sekarang Anda dapat mendaftarkan kredensial baru dan menampilkan informasi tentang kredensial tersebut. Anda dapat mencobanya di situs aktif.
Kode akhir untuk bagian ini
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. Mengautentikasi pengguna dengan sidik jari
Anda sekarang memiliki kredensial terdaftar dan siap digunakan sebagai cara untuk mengautentikasi pengguna. Sekarang, tambahkan fungsi autentikasi ulang ke situs. Berikut adalah pengalaman pengguna:
Saat berada di halaman /reauth
, pengguna akan melihat tombol Authenticate jika autentikasi biometrik memungkinkan. Autentikasi dengan sidik jari (UVPA) dimulai saat pengguna mengetuk Authenticate, berhasil mengautentikasi, lalu membuka halaman /home
. Jika autentikasi biometrik tidak tersedia atau autentikasi dengan biometrik gagal, UI akan kembali untuk menggunakan formulir sandi yang ada.
Membuat fungsi authenticate()
Buat fungsi yang disebut authenticate()
, yang memverifikasi identitas pengguna dengan sidik jari. Tambahkan kode JavaScript di sini:
public/client.js
export const authenticate = async () => {
};
Mendapatkan verifikasi login dan opsi lainnya dari endpoint server
- Sebelum autentikasi, periksa apakah pengguna memiliki ID kredensial tersimpan dan tetapkan sebagai parameter kueri jika pengguna memilikinya.
Jika Anda memberikan ID kredensial beserta opsi lainnya, server dapat memberikan allowCredentials
yang relevan dan ini akan membuat verifikasi pengguna menjadi andal.
public/client.js
const opts = {};
let url = '/auth/signinRequest';
const credId = localStorage.getItem(`credId`);
if (credId) {
url += `?credId=${encodeURIComponent(credId)}`;
}
- Sebelum meminta pengguna untuk mengautentikasi, minta server untuk mengirimkan kembali verifikasi dan parameter lainnya. Panggil
_fetch()
denganopts
sebagai argumen untuk mengirim permintaan POST ke server.
public/client.js
const options = await _fetch(url, opts);
Berikut adalah opsi contoh yang harus Anda terima (sesuai dengan PublicKeyCredentialRequestOptions
).
{
"challenge": "...",
"timeout": 1800000,
"rpId": "webauthn-codelab.glitch.me",
"userVerification": "required",
"allowCredentials": [
{
"id": "...",
"type": "public-key",
"transports": [
"internal"
]
}
]
}
Opsi yang paling penting di sini adalah allowCredentials
. Saat Anda menerima opsi dari server, allowCredentials
harus berupa objek tunggal dalam array atau array kosong, bergantung pada apakah kredensial dengan ID dalam parameter kueri ditemukan di sisi server.
- Resolve promise dengan
null
jikaallowCredentials
adalah array kosong sehingga UI kembali untuk meminta sandi.
if (options.allowCredentials.length === 0) {
console.info('No registered credentials found.');
return Promise.resolve(null);
}
Memverifikasi pengguna secara lokal dan mendapatkan kredensial
- Karena opsi ini dikirimkan dan dienkode untuk melalui protokol HTTP, konversikan beberapa parameter kembali ke biner, khususnya
challenge
dan instanceid
yang disertakan dalam arrayallowCredentials
:
public/client.js
options.challenge = base64url.decode(options.challenge);
for (let cred of options.allowCredentials) {
cred.id = base64url.decode(cred.id);
}
- Panggil metode
navigator.credentials.get()
untuk memverifikasi identitas pengguna dengan UVPA.
public/client.js
const cred = await navigator.credentials.get({
publicKey: options
});
Setelah pengguna memverifikasi identitasnya, Anda akan menerima objek kredensial yang dapat dikirim ke server dan mengautentikasikan pengguna.
Memverifikasi kredensial
Berikut adalah contoh objek PublicKeyCredential
(response
adalah AuthenticatorAssertionResponse
) yang akan Anda terima:
{
"id": "...",
"type": "public-key",
"rawId": "...",
"response": {
"clientDataJSON": "...",
"authenticatorData": "...",
"signature": "...",
"userHandle": ""
}
}
- Enkodekan parameter biner kredensial agar dapat dikirim ke server sebagai string:
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,
};
}
- Kirim objek ke server dan, jika menampilkan
HTTP code 200
, anggaplah pengguna berhasil login:
public/client.js
return await _fetch(`/auth/signinResponse`, credential);
Anda sekarang memiliki fungsi authentication()
yang lengkap.
Kode akhir untuk bagian ini
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. Mengaktifkan pengalaman autentikasi ulang
Mem-build UI
Saat pengguna kembali, Anda ingin mereka mengautentikasi ulang semudah dan seaman mungkin. Di sinilah autentikasi biometrik berfungsi. Namun, ada kasus saat autentikasi biometrik mungkin tidak berfungsi:
- UVPA tidak tersedia.
- Pengguna belum mendaftarkan kredensial apa pun di perangkatnya.
- Penyimpanan dihapus dan perangkat tidak lagi mengingat ID kredensial.
- Pengguna tidak dapat memverifikasi identitasnya karena beberapa alasan, seperti saat jari mereka basah atau mereka mengenakan masker.
Itulah sebabnya Anda harus selalu memberikan opsi login lain sebagai cadangan. Dalam codelab ini, gunakan solusi sandi berbasis formulir.
- Tambahkan UI untuk menampilkan tombol autentikasi yang memanggil autentikasi biometrik selain formulir sandi.
Gunakan class hidden
untuk menampilkan dan menyembunyikan salah satunya secara selektif, bergantung pada status pengguna.
views/reauth.html
<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>
- Tambahkan
class="hidden"
ke formulir:
views/reauth.html
<form id="form" method="POST" action="/auth/password" class="hidden">
Deteksi fitur dan ketersediaan UVPA
Pengguna harus login menggunakan sandi jika salah satu kondisi berikut terpenuhi:
- WebAuthn tidak tersedia.
- UVPA tidak tersedia.
- ID kredensial untuk UVPA ini tidak dapat ditemukan.
Tampilkan tombol autentikasi secara selektif atau sembunyikan:
views/reauth.html
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');
}
Kembali ke formulir sandi
Pengguna juga dapat memilih untuk login dengan sandi.
Tampilkan formulir sandi dan sembunyikan tombol autentikasi saat pengguna mengklik Sign in with password:.
views/reauth.html
const cancel = document.querySelector('#cancel');
cancel.addEventListener('click', e => {
form.classList.remove('hidden');
document
.querySelector('#uvpa_available')
.classList.add('hidden');
});
Memanggil autentikasi biometrik
Terakhir, aktifkan autentikasi biometrik.
- Tambahkan
authenticate
ke pernyataanimport
yang ada:
views/reauth.html
import { _fetch, authenticate } from '/client.js';
- Panggil
authenticate()
saat pengguna mengetuk Authenticate untuk memulai autentikasi biometrik.
Pastikan bahwa kegagalan pada autentikasi biometrik akan mengembalikan pengguna ke formulir sandi.
views/reauth.html
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');
});
});
Kode akhir untuk bagian ini
views/reauth.html
...
<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. Selamat!
Anda telah menyelesaikan codelab ini.
Pelajari lebih lanjut
- Autentikasi Web: API untuk mengakses Kredensial Kunci Publik Level 1
- Pengantar WebAuthn API
- Workshop FIDO WebAuthn
- Panduan WebAuthn: DUOSEC
- Android FIDO2 API pertama Anda
Terima kasih banyak kepada Yuriy Ackermann dari FIDO Alliance atas bantuan Anda.