1. Başlamadan önce
Şifre yerine geçiş anahtarı kullanmak, web sitelerinin kullanıcı hesaplarını daha güvenli, basit ve kolay kullanılabilir hale getirmesinin harika bir yoludur. Geçiş anahtarı sayesinde kullanıcılar, cihazın ekran kilidi özelliğini (ör. parmak izi, yüz veya cihaz PIN'i) kullanarak web sitesinde ya da uygulamada oturum açabilir. Kullanıcının geçiş anahtarıyla oturum açabilmesi için geçiş anahtarının oluşturulması, bir kullanıcı hesabıyla ilişkilendirilmesi ve herkese açık anahtarının bir sunucuda depolanması gerekir.
Bu codelab'de, temel form tabanlı kullanıcı adı ve şifreyle oturum açma özelliğini, geçiş anahtarlarını destekleyen ve aşağıdakileri içeren bir oturum açma özelliğine dönüştüreceksiniz:
- Kullanıcı giriş yaptıktan sonra geçiş anahtarı oluşturan bir düğme.
- Kayıtlı geçiş anahtarlarının listesini gösteren bir kullanıcı arayüzü.
- Kullanıcıların, form otomatik doldurma özelliğiyle kayıtlı bir geçiş anahtarıyla oturum açmasına olanak tanıyan mevcut oturum açma formu.
Ön koşullar
- Temel seviyede JavaScript bilgisi
- Geçiş anahtarları hakkında temel bilgi
- Web Authentication API (WebAuthn) hakkında temel bilgiler
Neler öğreneceksiniz?
- Geçiş anahtarı oluşturma
- Kullanıcıların kimliğini geçiş anahtarıyla doğrulama
- Formların oturum açma seçeneği olarak geçiş anahtarı önermesine izin verme
İhtiyacınız olanlar
Aşağıdaki cihaz kombinasyonlarından biri:
- Android 9 veya sonraki sürümlerin yüklü olduğu bir Android cihazda Google Chrome (tercihen biyometrik sensörlü)
- Windows 10 veya sonraki bir sürümü çalıştıran bir Windows cihazda Chrome
- iOS 16 veya sonraki sürümlerin yüklü olduğu bir iPhone ya da iPadOS 16 veya sonraki sürümlerin yüklü olduğu bir iPad ile Safari 16 veya sonraki sürümler
- macOS Ventura veya sonraki bir sürümü çalıştıran bir Apple masaüstü cihazda Safari 16 ya da sonraki bir sürüm veya Chrome.
2. Hazırlanın
Bu codelab'de, istemci ve sunucu tarafı kodunu JavaScript ile düzenlemenize ve yalnızca tarayıcıdan dağıtmanıza olanak tanıyan Glitch adlı bir hizmeti kullanacaksınız.
Projeyi açın.
- Projeyi Glitch'te açın.
- Glitch projesini çatallamak için Remix'i (Remiks) tıklayın.
- Glitch'in alt kısmındaki gezinme menüsünde Önizleme > Yeni pencerede önizleme'yi tıklayın. Tarayıcınızda başka bir sekme açılır.
Web sitesinin ilk durumunu inceleyin
- Önizleme sekmesinde rastgele bir kullanıcı adı girip Sonraki'yi tıklayın.
- Rastgele bir şifre girip Oturum aç'ı tıklayın. Şifre yoksayılır ancak kimliğiniz doğrulanır ve ana sayfaya yönlendirilirsiniz.
- Görünen adınızı değiştirmek istiyorsanız bunu yapın. İlk durumda yapabileceğiniz tek şey budur.
- Oturumu kapat'ı tıklayın.
Bu durumda kullanıcıların her oturum açtıklarında şifre girmesi gerekir. Kullanıcıların cihazın ekran kilidi işlevini kullanarak oturum açabilmesi için bu forma geçiş anahtarı desteği ekleyin. Son durumu https://passkeys-codelab.glitch.me/ adresinde deneyebilirsiniz.
Geçiş anahtarlarının işleyiş şekli hakkında daha fazla bilgi için Geçiş anahtarları nasıl çalışır? başlıklı makaleyi inceleyin.
3. Geçiş anahtarı oluşturma özelliği ekleme
Kullanıcıların geçiş anahtarıyla kimlik doğrulaması yapmasına izin vermek için onlara geçiş anahtarı oluşturma ve kaydetme, ayrıca ortak anahtarını sunucuda saklama olanağı vermeniz gerekir.
Kullanıcının şifreyle giriş yapmasından sonra geçiş anahtarı oluşturmasına izin vermek ve /home
sayfasında kullanıcıların geçiş anahtarı oluşturmasına ve kayıtlı tüm geçiş anahtarlarının listesini görmesine olanak tanıyan bir kullanıcı arayüzü eklemek istiyorsunuz. Bir sonraki bölümde, geçiş anahtarı oluşturup kaydeden bir işlev oluşturacaksınız.
registerCredential()
işlevini oluşturma
- Glitch'te
public/client.js
dosyasına gidin ve sonuna kaydırın. - İlgili yorumun ardından şu
registerCredential()
işlevini ekleyin:
public/client. js
// TODO: Add an ability to create a passkey: Create the registerCredential() function. export async function registerCredential() { // TODO: Add an ability to create a passkey: Obtain the challenge and other options from the server endpoint. // TODO: Add an ability to create a passkey: Create a credential. // TODO: Add an ability to create a passkey: Register the credential to the server endpoint. };
Bu işlev, sunucuda bir geçiş anahtarı oluşturup kaydeder.
Sunucu uç noktasından sorguyu ve diğer seçenekleri alma
Geçiş anahtarı oluşturulmadan önce, sunucudan WebAuthn'e iletilecek parametreleri (ör. sorgu) istemeniz gerekir. WebAuthn, kullanıcının geçiş anahtarı oluşturmasına ve geçiş anahtarıyla kimliğini doğrulamasına olanak tanıyan bir tarayıcı API'sidir. Neyse ki bu codelab'de bu tür parametrelerle yanıt veren bir sunucu uç noktanız zaten var.
- Sunucu uç noktasından sorguyu ve diğer seçenekleri almak için ilgili yorumdan sonra
registerCredential()
işlevinin gövdesine aşağıdaki kodu ekleyin:
public/client.js
// TODO: Add an ability to create a passkey: Obtain the challenge and other options from the server endpoint. const options = await _fetch('/auth/registerRequest');
Aşağıdaki kod snippet'inde, sunucudan aldığınız örnek seçenekler yer almaktadır:
{ challenge: *****, rp: { id: "example.com", }, user: { id: *****, name: "john78", displayName: "John", }, pubKeyCredParams: [{ alg: -7, type: "public-key" },{ alg: -257, type: "public-key" }], excludeCredentials: [{ id: *****, type: 'public-key', transports: ['internal', 'hybrid'], }], authenticatorSelection: { authenticatorAttachment: "platform", requireResidentKey: true, } }
Sunucu ile istemci arasındaki protokol, WebAuthn spesifikasyonunun bir parçası değildir. Ancak bu codelab'in sunucusu, WebAuthn navigator.credentials.create()
API'sine iletilen PublicKeyCredentialCreationOptions
sözlüğüne mümkün olduğunca benzer bir JSON döndürecek şekilde tasarlanmıştır.
Aşağıdaki tablo kapsamlı olmasa da PublicKeyCredentialCreationOptions
sözlüğündeki önemli parametreleri içerir:
Parametreler | Açıklamalar |
Bu kayıt için | |
Kullanıcının benzersiz kimliği. Bu değer, e-posta adresleri veya kullanıcı adları gibi kişisel kimlik bilgilerini içermeyen bir | |
Bu alan, kullanıcının tanıdığı bir hesap için benzersiz bir tanımlayıcı (ör. e-posta adresi veya kullanıcı adı) içermelidir. Hesap seçicide gösterilir. (Kullanıcı adı kullanıyorsanız şifre kimlik doğrulamadaki değerle aynı değeri kullanın.) | |
Bu alan, hesap için isteğe bağlı olarak girilebilen, kullanıcı dostu bir addır. Benzersiz olması gerekmez ve kullanıcının seçtiği ad olabilir. Web sitenizde buraya eklenecek uygun bir değer yoksa boş bir dize iletin. Bu bilgi, tarayıcıya bağlı olarak hesap seçicide gösterilebilir. | |
Güvenen taraf (RP) kimliği bir alandır. Bir web sitesi, alanını veya kaydedilebilir bir sonek belirtebilir. Örneğin, bir RP'nin kaynağı https://login.example.com:1337 ise RP kimliği | |
Bu alan, RP'nin desteklediği ortak anahtar algoritmalarını belirtir. Bu değeri | |
Aynı cihazın iki kez kaydedilmesini önlemek için, daha önce kaydedilmiş kimlik bilgilerinin bir listesini sağlar. Sağlanırsa | |
| |
Boole | |
|
Kimlik bilgisi oluşturma
registerCredential()
işlevinin gövdesinde, ilgili yorumdan sonra Base64URL ile kodlanmış bazı parametreleri (özellikleuser.id
vechallenge
dizeleri ileexcludeCredentials
dizisine dahil edilenid
dizesinin örnekleri) tekrar ikiliye dönüştürün:
public/client.js
// TODO: Add an ability to create a passkey: Create a credential. // Base64URL decode some values. 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); } }
- Sonraki satırda
authenticatorSelection.authenticatorAttachment
değerini"platform"
,authenticatorSelection.requireResidentKey
değerini isetrue
olarak ayarlayın. Bu, yalnızca keşfedilebilir kimlik bilgisi özelliğine sahip bir platform kimlik doğrulayıcısının (cihazın kendisi) kullanılmasına olanak tanır.
public/client.js
// Use platform authenticator and discoverable credential. options.authenticatorSelection = { authenticatorAttachment: 'platform', requireResidentKey: true }
- Bir sonraki satırda, kimlik bilgisi oluşturmak için
navigator.credentials.create()
yöntemini çağırın.
public/client.js
// Invoke the WebAuthn create() method. const cred = await navigator.credentials.create({ publicKey: options, });
Bu çağrıyla tarayıcı, kullanıcının kimliğini cihazın ekran kilidiyle doğrulamaya çalışır.
Kimlik bilgisini sunucu uç noktasına kaydetme
Kullanıcı kimliğini doğruladıktan sonra bir geçiş anahtarı oluşturulup saklanır. Web sitesi, geçiş anahtarını kaydetmek için sunucuya gönderebileceğiniz bir ortak anahtar içeren kimlik bilgisi nesnesi alır.
Aşağıdaki kod snippet'inde örnek bir kimlik bilgisi nesnesi yer almaktadır:
{ "id": *****, "rawId": *****, "type": "public-key", "response": { "clientDataJSON": *****, "attestationObject": *****, "transports": ["internal", "hybrid"] }, "authenticatorAttachment": "platform" }
Aşağıdaki tablo kapsamlı olmasa da PublicKeyCredential
nesnesindeki önemli parametreleri içerir:
Parametreler | Açıklamalar |
Oluşturulan geçiş anahtarının Base64URL kodlu kimliği. Bu kimlik, tarayıcının kimlik doğrulama sırasında cihazda eşleşen bir geçiş anahtarı olup olmadığını belirlemesine yardımcı olur. Bu değer, arka uçtaki veritabanında depolanmalıdır. | |
Kimlik bilgisinin kimliğinin | |
İstemci verilerini kodlayan bir | |
| |
Cihazın desteklediği aktarımların listesi: | |
Bu kimlik bilgisi, geçiş anahtarı oluşturmaya uygun bir cihazda oluşturulduğunda |
Kimlik bilgisi nesnesini sunucuya göndermek için aşağıdaki adımları uygulayın:
- Kimlik bilgisinin ikili parametrelerini Base64URL olarak kodlayın. Böylece, sunucuya dize olarak iletilebilir:
public/client.js
// TODO: Add an ability to create a passkey: Register the credential to the server endpoint. const credential = {}; credential.id = cred.id; credential.rawId = cred.id; // Pass a Base64URL encoded ID string. credential.type = cred.type; // The authenticatorAttachment string in the PublicKeyCredential object is a new addition in WebAuthn L3. if (cred.authenticatorAttachment) { credential.authenticatorAttachment = cred.authenticatorAttachment; } // Base64URL encode some values. const clientDataJSON = base64url.encode(cred.response.clientDataJSON); const attestationObject = base64url.encode(cred.response.attestationObject); // Obtain transports. const transports = cred.response.getTransports ? cred.response.getTransports() : []; credential.response = { clientDataJSON, attestationObject, transports };
- Sonraki satırda, nesneyi sunucuya gönderin:
public/client.js
return await _fetch('/auth/registerResponse', credential);
Programı çalıştırdığınızda sunucu, kimlik bilgisinin kaydedildiğini belirten HTTP code 200
değerini döndürür.
Artık registerCredential()
işlevinin tamamına sahipsiniz.
Bu bölümün çözüm kodunu inceleyin.
public/client.js
// TODO: Add an ability to create a passkey: Create the registerCredential() function. export async function registerCredential() { // TODO: Add an ability to create a passkey: Obtain the challenge and other options from server endpoint. const options = await _fetch('/auth/registerRequest'); // TODO: Add an ability to create a passkey: Create a credential. // Base64URL decode some values. 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); } } // Use platform authenticator and discoverable credential. options.authenticatorSelection = { authenticatorAttachment: 'platform', requireResidentKey: true } // Invoke the WebAuthn create() method. const cred = await navigator.credentials.create({ publicKey: options, }); // TODO: Add an ability to create a passkey: Register the credential to the server endpoint. const credential = {}; credential.id = cred.id; credential.rawId = cred.id; // Pass a Base64URL encoded ID string. credential.type = cred.type; // The authenticatorAttachment string in the PublicKeyCredential object is a new addition in WebAuthn L3. if (cred.authenticatorAttachment) { credential.authenticatorAttachment = cred.authenticatorAttachment; } // Base64URL encode some values. const clientDataJSON = base64url.encode(cred.response.clientDataJSON); const attestationObject = base64url.encode(cred.response.attestationObject); // Obtain transports. const transports = cred.response.getTransports ? cred.response.getTransports() : []; credential.response = { clientDataJSON, attestationObject, transports }; return await _fetch('/auth/registerResponse', credential); };
4. Geçiş anahtarı kimlik bilgilerini kaydetmek ve yönetmek için bir kullanıcı arayüzü oluşturun
registerCredential()
işlevi kullanıma sunulduğundan, bu işlevi çağırmak için bir düğmeye ihtiyacınız var. Ayrıca, kayıtlı geçiş anahtarlarının listesini de göstermeniz gerekir.
Yer tutucu HTML ekleme
- Glitch'te
views/home.html
dosyasına gidin. - İlgili yorumun ardından, geçiş anahtarı kaydetme düğmesini ve geçiş anahtarlarının listesini gösteren bir kullanıcı arayüzü yer tutucusu ekleyin:
views/home.html
<!-- TODO: Add an ability to create a passkey: Add placeholder HTML. --> <section> <h3 class="mdc-typography mdc-typography--headline6"> Your registered passkeys:</h3> <div id="list"></div> </section> <p id="message" class="instructions"></p> <mwc-button id="create-passkey" class="hidden" icon="fingerprint" raised>Create a passkey</mwc-button>
div#list
öğesi, listenin yer tutucusudur.
Geçiş anahtarı desteğini kontrol etme
Yalnızca geçiş anahtarlarını destekleyen cihazlara sahip kullanıcılara geçiş anahtarı oluşturma seçeneğini göstermek için öncelikle WebAuthn'nin kullanılabilir olup olmadığını kontrol etmeniz gerekir. Bu durumda, Geçiş anahtarı oluştur düğmesini göstermek için hidden
sınıfını kaldırmanız gerekir.
Bir ortamın geçiş anahtarlarını destekleyip desteklemediğini kontrol etmek için aşağıdaki adımları uygulayın:
- İlgili yorumdan sonra
views/home.html
dosyasının sonunawindow.PublicKeyCredential
,PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable
vePublicKeyCredential.isConditionalMediationAvailable
true
ise yürütülecek bir koşul yazın.
views/home.html
// TODO: Add an ability to create a passkey: Check for passkey support. const createPasskey = $('#create-passkey'); // Feature detections if (window.PublicKeyCredential && PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable && PublicKeyCredential.isConditionalMediationAvailable) {
- Koşullu ifadenin gövdesinde, cihazın geçiş anahtarı oluşturup oluşturamayacağını ve ardından geçiş anahtarının form otomatik doldurma işleminde önerilip önerilemeyeceğini kontrol edin.
views/home.html
try { const results = await Promise.all([ // Is platform authenticator available in this browser? PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(), // Is conditional UI available in this browser? PublicKeyCredential.isConditionalMediationAvailable() ]);
- Tüm koşullar karşılanıyorsa geçiş anahtarı oluşturma düğmesini gösterin. Aksi takdirde uyarı mesajı gösterilir.
views/home.html
if (results.every(r => r === true)) { // If conditional UI is available, reveal the Create a passkey button. createPasskey.classList.remove('hidden'); } else { // If conditional UI isn't available, show a message. $('#message').innerText = 'This device does not support passkeys.'; } } catch (e) { console.error(e); } } else { // If WebAuthn isn't available, show a message. $('#message').innerText = 'This device does not support passkeys.'; }
Kayıtlı geçiş anahtarlarını listede görüntüleme
- Kayıtlı geçiş anahtarlarını sunucudan getiren ve bunları listede oluşturulan bir
renderCredentials()
işlevi tanımlayın. Neyse ki, oturum açmış kullanıcı için kayıtlı geçiş anahtarlarını getirmek üzere/auth/getKeys
sunucu uç noktasına zaten sahipsiniz.
views/home.html
// TODO: Add an ability to create a passkey: Render registered passkeys in a list. async function renderCredentials() { const res = await _fetch('/auth/getKeys'); const list = $('#list'); const creds = html`${res.length > 0 ? html` <mwc-list> ${res.map(cred => html` <mwc-list-item> <div class="list-item"> <div class="entity-name"> <span>${cred.name || 'Unnamed' }</span> </div> <div class="buttons"> <mwc-icon-button data-cred-id="${cred.id}" data-name="${cred.name || 'Unnamed' }" @click="${rename}" icon="edit"></mwc-icon-button> <mwc-icon-button data-cred-id="${cred.id}" @click="${remove}" icon="delete"></mwc-icon-button> </div> </div> </mwc-list-item>`)} </mwc-list>` : html` <mwc-list> <mwc-list-item>No credentials found.</mwc-list-item> </mwc-list>`}`; render(creds, list); };
- Bir sonraki satırda, kullanıcı
/home
sayfasına geldiğinde kayıtlı geçiş anahtarlarını başlatma olarak hemen görüntülemek içinrenderCredentials()
işlevini çağırın.
views/home.html
renderCredentials();
Geçiş anahtarı oluşturma ve kaydetme
Geçiş anahtarı oluşturup kaydetmek için daha önce uyguladığınız registerCredential()
işlevini çağırmanız gerekir.
Geçiş anahtarı oluştur düğmesini tıkladığınızda registerCredential()
işlevini tetiklemek için aşağıdaki adımları uygulayın:
- Yer tutucu HTML'den sonraki dosyada aşağıdaki
import
ifadesini bulun:
views/home.html
import { $, _fetch, loading, updateCredential, unregisterCredential, } from '/client.js';
import
ifadesinin gövdesinin sonunaregisterCredential()
işlevini ekleyin.
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey. import { $, _fetch, loading, updateCredential, unregisterCredential, registerCredential } from '/client.js';
- Dosyanın sonuna, ilgili yorumdan sonra
register()
işlevini çağıran birregisterCredential()
işlevi ve yükleme kullanıcı arayüzü tanımlayın ve kayıttan sonrarenderCredentials()
işlevini çağırın. Bu, tarayıcının geçiş anahtarı oluşturduğunu ve bir sorun olduğunda hata mesajı gösterdiğini netleştirir.
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey. async function register() { try { // Start the loading UI. loading.start(); // Start creating a passkey. await registerCredential(); // Stop the loading UI. loading.stop(); // Render the updated passkey list. renderCredentials();
register()
işlevinin gövdesinde istisnaları yakalayın.navigator.credentials.create()
yöntemi, cihazda zaten bir geçiş anahtarı varsaInvalidStateError
hatası verir. Bu,excludeCredentials
dizisiyle incelenir. Bu durumda kullanıcıya alakalı bir mesaj gösterirsiniz. Kullanıcı kimlik doğrulama iletişim kutusunu iptal ettiğinde deNotAllowedError
hatası oluşturur. Bu durumda sessizce yoksayarsınız.
views/home.html
} catch (e) { // Stop the loading UI. loading.stop(); // An InvalidStateError indicates that a passkey already exists on the device. if (e.name === 'InvalidStateError') { alert('A passkey already exists for this device.'); // A NotAllowedError indicates that the user canceled the operation. } else if (e.name === 'NotAllowedError') { Return; // Show other errors in an alert. } else { alert(e.message); console.error(e); } } };
register()
işlevinden sonraki satırda, Geçiş anahtarı oluştur düğmesi içinregister()
işlevini birclick
etkinliğine ekleyin.
views/home.html
createPasskey.addEventListener('click', register);
Bu bölümün çözüm kodunu inceleyin.
views/home.html
<!-- TODO: Add an ability to create a passkey: Add placeholder HTML. --> <section> <h3 class="mdc-typography mdc-typography--headline6"> Your registered passkeys:</h3> <div id="list"></div> </section> <p id="message" class="instructions"></p> <mwc-button id="create-passkey" class="hidden" icon="fingerprint" raised>Create a passkey</mwc-button>
views/home.html
// TODO: Add an ability to create a passkey: Create and register a passkey. import { $, _fetch, loading, updateCredential, unregisterCredential, registerCredential } from '/client.js';
views/home.html
// TODO: Add an ability to create a passkey: Check for passkey support. const createPasskey = $('#create-passkey'); // Feature detections if (window.PublicKeyCredential && PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable && PublicKeyCredential.isConditionalMediationAvailable) { try { const results = await Promise.all([ // Is platform authenticator available in this browser? PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(), // Is conditional UI available in this browser? PublicKeyCredential.isConditionalMediationAvailable() ]); if (results.every(r => r === true)) { // If conditional UI is available, reveal the Create a passkey button. createPasskey.classList.remove('hidden'); } else { // If conditional UI isn't available, show a message. $('#message').innerText = 'This device does not support passkeys.'; } } catch (e) { console.error(e); } } else { // If WebAuthn isn't available, show a message. $('#message').innerText = 'This device does not support passkeys.'; } // TODO: Add an ability to create a passkey: Render registered passkeys in a list. async function renderCredentials() { const res = await _fetch('/auth/getKeys'); const list = $('#list'); const creds = html`${res.length > 0 ? html` <mwc-list> ${res.map(cred => html` <mwc-list-item> <div class="list-item"> <div class="entity-name"> <span>${cred.name || 'Unnamed' }</span> </div> <div class="buttons"> <mwc-icon-button data-cred-id="${cred.id}" data-name="${cred.name || 'Unnamed' }" @click="${rename}" icon="edit"></mwc-icon-button> <mwc-icon-button data-cred-id="${cred.id}" @click="${remove}" icon="delete"></mwc-icon-button> </div> </div> </mwc-list-item>`)} </mwc-list>` : html` <mwc-list> <mwc-list-item>No credentials found.</mwc-list-item> </mwc-list>`}`; render(creds, list); }; renderCredentials(); // TODO: Add an ability to create a passkey: Create and register a passkey. async function register() { try { // Start the loading UI. loading.start(); // Start creating a passkey. await registerCredential(); // Stop the loading UI. loading.stop(); // Render the updated passkey list. renderCredentials(); } catch (e) { // Stop the loading UI. loading.stop(); // An InvalidStateError indicates that a passkey already exists on the device. if (e.name === 'InvalidStateError') { alert('A passkey already exists for this device.'); // A NotAllowedError indicates that the user canceled the operation. } else if (e.name === 'NotAllowedError') { Return; // Show other errors in an alert. } else { alert(e.message); console.error(e); } } }; createPasskey.addEventListener('click', register);
Dene
Şimdiye kadarki tüm adımları uyguladıysanız web sitesinde geçiş anahtarları oluşturma, kaydetme ve görüntüleme özelliğini etkinleştirdiniz.
Bu özelliği denemek için aşağıdaki adımları uygulayın:
- Önizleme sekmesinde rastgele bir kullanıcı adı ve şifreyle oturum açın.
- Geçiş anahtarı oluştur'u tıklayın.
- Kimliğinizi cihazın ekran kilidiyle doğrulayın.
- Bir geçiş anahtarının kaydedildiğini ve web sayfasının Kayıtlı geçiş anahtarlarınız bölümünde gösterildiğini onaylayın.
Kayıtlı geçiş anahtarlarını yeniden adlandırma ve kaldırma
Kayıtlı geçiş anahtarlarını listede yeniden adlandırabilir veya silebilirsiniz. Nasıl çalıştığını, codelab'de yer alan koddan kontrol edebilirsiniz.
Chrome'da, kayıtlı geçiş anahtarlarını masaüstünde chrome://settings/passkeys adresinden veya Android'de ayarlardaki şifre yöneticisinden kaldırabilirsiniz.
Diğer platformlarda kayıtlı geçiş anahtarlarını yeniden adlandırma ve kaldırma hakkında bilgi edinmek için ilgili platformların destek sayfalarına bakın.
5. Geçiş anahtarıyla kimlik doğrulama özelliği ekleme
Kullanıcılar artık geçiş anahtarı oluşturup kaydedebilir ve web sitenizde güvenli bir şekilde kimlik doğrulamak için kullanabilir. Şimdi web sitenize geçiş anahtarı kimlik doğrulama özelliği eklemeniz gerekiyor.
authenticate()
işlevini oluşturma
public/client.js
dosyasında, ilgili yorumun ardındanauthenticate()
adlı bir işlev oluşturun. Bu işlev, kullanıcıyı önce yerel olarak, ardından sunucuya karşı doğrular:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Create the authenticate() function. export async function authenticate() { // TODO: Add an ability to authenticate with a passkey: Obtain the challenge and other options from the server endpoint. // TODO: Add an ability to authenticate with a passkey: Locally verify the user and get a credential. // TODO: Add an ability to authenticate with a passkey: Verify the credential. };
Sunucu uç noktasından sorgulama ve diğer seçenekleri alma
Kullanıcıdan kimlik doğrulaması yapmasını istemeden önce, sunucudan WebAuthn'de iletilecek parametreleri (ör. bir sorgu) istemeniz gerekir.
- İlgili yorumdan sonra
authenticate()
işlevinin gövdesinde, sunucuyaPOST
isteği göndermek için_fetch()
işlevini çağırın:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Obtain the challenge and other options from the server endpoint. const options = await _fetch('/auth/signinRequest');
Bu codelab'deki sunucu, WebAuthn navigator.credentials.get()
API'sine iletilen PublicKeyCredentialRequestOptions
sözlüğüne mümkün olduğunca benzer JSON döndürecek şekilde tasarlanmıştır. Aşağıdaki kod snippet'inde, almanız gereken örnek seçenekler yer almaktadır:
{ "challenge": *****, "rpId": "passkeys-codelab.glitch.me", "allowCredentials": [] }
Aşağıdaki tablo kapsamlı olmasa da PublicKeyCredentialRequestOptions
sözlüğündeki önemli parametreleri içerir:
Parametreler | Açıklamalar |
| |
RP kimliği bir alandır. Bir web sitesi, alanını veya kaydedilebilir bir sonek belirtebilir. Bu değer, geçiş anahtarı oluşturulurken kullanılan | |
Bu özellik, bu kimlik doğrulama için uygun kimlik doğrulayıcıları bulmak amacıyla kullanılır. Tarayıcının hesap seçici göstermesine izin vermek için boş bir dizi iletin veya belirtmeyin. | |
|
Kullanıcıyı yerel olarak doğrulama ve kimlik bilgisi alma
authenticate()
işlevinin gövdesinde, ilgili yorumdan sonrachallenge
parametresini tekrar ikiliye dönüştürün:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Locally verify the user and get a credential. // Base64URL decode the challenge. options.challenge = base64url.decode(options.challenge);
- Kullanıcı kimlik doğrulaması yaptığında hesap seçiciyi açmak için
allowCredentials
parametresine boş bir dizi iletin:
public/client.js
// An empty allowCredentials array invokes an account selector by discoverable credentials. options.allowCredentials = [];
Hesap seçici, kullanıcının geçiş anahtarıyla saklanan bilgilerini kullanır.
navigator.credentials.get()
yönteminimediation: 'conditional'
seçeneğiyle birlikte çağırın:
public/client.js
// Invoke the WebAuthn get() method. const cred = await navigator.credentials.get({ publicKey: options, // Request a conditional UI. mediation: 'conditional' });
Bu seçenek, tarayıcıya form otomatik doldurma işleminin bir parçası olarak koşullu geçiş anahtarı önermesi talimatını verir.
Kimlik bilgisini doğrulama
Kullanıcı kimliğini yerel olarak doğruladıktan sonra, sunucuda doğrulayabileceğiniz bir imza içeren bir kimlik bilgisi nesnesi alırsınız.
Aşağıdaki kod snippet'inde bir örnek PublicKeyCredential
nesnesi yer almaktadır:
{ "id": *****, "rawId": *****, "type": "public-key", "response": { "clientDataJSON": *****, "authenticatorData": *****, "signature": *****, "userHandle": ***** }, authenticatorAttachment: "platform" }
Aşağıdaki tablo kapsamlı olmasa da PublicKeyCredential
nesnesindeki önemli parametreleri içerir:
Parametreler | Açıklamalar |
Kimliği doğrulanmış geçiş anahtarı kimliğinin Base64URL kodlu sürümü. | |
Kimlik bilgisinin kimliğinin | |
İstemci verilerinin | |
Kimlik doğrulayıcı verilerinin | |
İmzanın | |
Oluşturma sırasında ayarlanan kullanıcı kimliğini içeren bir | |
Bu kimlik bilgisi yerel cihazdan geldiğinde |
Kimlik bilgisi nesnesini sunucuya göndermek için aşağıdaki adımları uygulayın:
authenticate()
işlevinin gövdesinde, ilgili yorumdan sonra kimlik bilgisinin ikili parametrelerini, sunucuya dize olarak iletilebilmesi için kodlayın:
public/client.js
// TODO: Add an ability to authenticate with a passkey: Verify the credential. const credential = {}; credential.id = cred.id; credential.rawId = cred.id; // Pass a Base64URL encoded ID string. credential.type = cred.type; // Base64URL encode some values. 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, };
- Nesneyi sunucuya gönderin:
public/client.js
return await _fetch(`/auth/signinResponse`, credential);
Programı çalıştırdığınızda sunucu, kimlik bilgisinin doğrulandığını belirten HTTP code 200
değerini döndürür.
Artık authentication()
işlevinin tüm özelliklerini kullanabilirsiniz.
Bu bölümün çözüm kodunu inceleyin.
public/client.js
// TODO: Add an ability to authenticate with a passkey: Create the authenticate() function. export async function authenticate() { // TODO: Add an ability to authenticate with a passkey: Obtain the challenge and other options from the server endpoint. const options = await _fetch('/auth/signinRequest'); // TODO: Add an ability to authenticate with a passkey: Locally verify the user and get a credential. // Base64URL decode the challenge. options.challenge = base64url.decode(options.challenge); // The empty allowCredentials array invokes an account selector by discoverable credentials. options.allowCredentials = []; // Invoke the WebAuthn get() function. const cred = await navigator.credentials.get({ publicKey: options, // Request a conditional UI. mediation: 'conditional' }); // TODO: Add an ability to authenticate with a passkey: Verify the credential. const credential = {}; credential.id = cred.id; credential.rawId = cred.id; // Pass a Base64URL encoded ID string. credential.type = cred.type; // Base64URL encode some values. 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. Tarayıcıda otomatik doldurma özelliğine geçiş anahtarları ekleme
Kullanıcı geri döndüğünde mümkün olduğunca kolay ve güvenli bir şekilde oturum açmasını istersiniz. Giriş sayfasına Geçiş anahtarıyla oturum aç düğmesi eklerseniz kullanıcı bu düğmeye basabilir, tarayıcının hesap seçicisinde bir geçiş anahtarı seçebilir ve kimliğini doğrulamak için ekran kilidini kullanabilir.
Ancak şifreden geçiş anahtarına geçiş, tüm kullanıcılar için aynı anda gerçekleşmez. Bu nedenle, tüm kullanıcılar geçiş anahtarlarına geçene kadar şifreleri kaldıramazsınız. Bu süre zarfında şifre tabanlı oturum açma formunu kullanmaya devam etmeniz gerekir. Ancak şifre formu ve geçiş anahtarı düğmesi bırakırsanız kullanıcılar oturum açmak için hangisini kullanacakları konusunda gereksiz bir seçim yapmak zorunda kalır. İdeal olan, basit bir oturum açma sürecidir.
Bu noktada koşullu kullanıcı arayüzü devreye girer. Koşullu kullanıcı arayüzü, şifrelere ek olarak otomatik doldurma öğelerinin bir parçası olarak geçiş anahtarı önermek için bir form giriş alanı oluşturabileceğiniz bir WebAuthn özelliğidir. Kullanıcı, otomatik doldurma önerilerinde bir geçiş anahtarına dokunursa kimliğini yerel olarak doğrulamak için cihazın ekran kilidini kullanması istenir. Kullanıcı işlemi, şifre tabanlı oturum açma işlemine neredeyse tamamen benzediği için bu, sorunsuz bir kullanıcı deneyimidir.
Koşullu kullanıcı arayüzünü etkinleştirme
Koşullu bir kullanıcı arayüzünü etkinleştirmek için tek yapmanız gereken bir giriş alanının autocomplete
özelliğine webauthn
jetonu eklemektir. Jeton ayarlandığında, ekran kilidi kullanıcı arayüzünü koşullu olarak tetiklemek için navigator.credentials.get()
yöntemini mediation: 'conditional'
dizesiyle çağırabilirsiniz.
- Koşullu bir kullanıcı arayüzünü etkinleştirmek için
view/index.html
dosyasındaki ilgili yorumdan sonra mevcut kullanıcı adı giriş alanlarını aşağıdaki HTML ile değiştirin:
view/index.html
<!-- TODO: Add passkeys to the browser autofill: Enable conditional UI. --> <input type="text" id="username" class="mdc-text-field__input" aria-labelledby="username-label" name="username" autocomplete="username webauthn" autofocus />
Özellikleri algılama, WebAuthn'i çağırma ve koşullu bir kullanıcı arayüzünü etkinleştirme
view/index.html
dosyasında, ilgili yorumdan sonraki mevcutimport
ifadesini aşağıdaki kodla değiştirin:
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI. import { $, _fetch, loading, authenticate } from "/client.js";
Bu kod, daha önce uyguladığınız authenticate()
işlevini içe aktarır.
window.PulicKeyCredential
nesnesinin kullanılabilir olduğunu vePublicKeyCredential.isConditionalMediationAvailable()
yönteminintrue
değeri döndürdüğünü onaylayın, ardındanauthenticate()
işlevini çağırın:
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI. if ( window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable ) { try { // Is conditional UI available in this browser? const cma = await PublicKeyCredential.isConditionalMediationAvailable(); if (cma) { // If conditional UI is available, invoke the authenticate() function. const user = await authenticate(); if (user) { // Proceed only when authentication succeeds. $("#username").value = user.username; loading.start(); location.href = "/home"; } else { throw new Error("User not found."); } } } catch (e) { loading.stop(); // A NotAllowedError indicates that the user canceled the operation. if (e.name !== "NotAllowedError") { console.error(e); alert(e.message); } } }
Bu bölümün çözüm kodunu inceleyin.
view/index.html
<!-- TODO: Add passkeys to the browser autofill: Enable conditional UI. --> <input type="text" id="username" class="mdc-text-field__input" aria-labelledby="username-label" name="username" autocomplete="username webauthn" autofocus />
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI. import { $, _fetch, loading, authenticate } from '/client.js';
view/index.html
// TODO: Add passkeys to the browser autofill: Detect features, invoke WebAuthn, and enable a conditional UI. // Is WebAuthn avaiable in this browser? if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) { try { // Is a conditional UI available in this browser? const cma= await PublicKeyCredential.isConditionalMediationAvailable(); if (cma) { // If a conditional UI is available, invoke the authenticate() function. const user = await authenticate(); if (user) { // Proceed only when authentication succeeds. $('#username').value = user.username; loading.start(); location.href = '/home'; } else { throw new Error('User not found.'); } } } catch (e) { loading.stop(); // A NotAllowedError indicates that the user canceled the operation. if (e.name !== 'NotAllowedError') { console.error(e); alert(e.message); } } }
Dene
Web sitenizde geçiş anahtarlarının oluşturulması, kaydedilmesi, gösterilmesi ve kimlik doğrulaması işlemlerini uyguladınız.
Bu özelliği denemek için aşağıdaki adımları uygulayın:
- Önizleme sekmesine gidin.
- Gerekirse oturumu kapatın.
- Kullanıcı adı metin kutusunu tıklayın. Bir iletişim kutusu açılır.
- Oturum açmak istediğiniz hesabı seçin.
- Kimliğinizi cihazın ekran kilidiyle doğrulayın.
/home
sayfasına yönlendirilir ve oturum açarsınız.
7. Tebrikler!
Bu codelab'i tamamladınız. Sorularınız varsa bunları FIDO-DEV posta listesinde veya StackOverflow'da passkey
etiketiyle sorun.