अपना पहला WebAuthn ऐप्लिकेशन बनाएं

1. शुरू करने से पहले

वेब ऑथेंटिकेशन एपीआई को WebAuthn भी कहा जाता है. इसकी मदद से, आप उपयोगकर्ताओं की पुष्टि करने के लिए, ऑरिजिन के दायरे वाले सार्वजनिक कुंजी के क्रेडेंशियल बना सकते हैं और उनका इस्तेमाल कर सकते हैं.

एपीआई, BLE, NFC, और यूएसबी-रोमिंग U2F या FIDO2 की पुष्टि करने वाले क्रेडेंशियल (जिन्हें सुरक्षा कुंजियां भी कहा जाता है) के साथ-साथ प्लैटफ़ॉर्म की पुष्टि करने वाले टूल के इस्तेमाल की सुविधा देता है. इसकी मदद से, उपयोगकर्ता अपने फ़िंगरप्रिंट या स्क्रीन लॉक की मदद से पुष्टि कर सकते हैं.

इस कोडलैब (कोड बनाना सीखना) में, आप फिर से पुष्टि करने की सुविधा वाली एक वेबसाइट बनाते हैं, जिसमें फ़िंगरप्रिंट सेंसर का इस्तेमाल होता है. फिर से पुष्टि करने से खाते का डेटा सुरक्षित रहता है. इसके लिए यह ज़रूरी है कि वेबसाइट में पहले से साइन इन किए हुए उपयोगकर्ता, वेबसाइट के अहम सेक्शन में जाने या कुछ तय समय के बाद वेबसाइट पर फिर से जाने की पुष्टि करें.

ज़रूरी बातें

  • WebAuthn के काम करने के तरीके की बुनियादी जानकारी
  • JavaScript की मदद से प्रोग्रामिंग से जुड़े बुनियादी कौशल

आप क्या कर पाएंगे!

  • फिर से पुष्टि करने की सुविधा वाली वेबसाइट बनाएं, जो फ़िंगरप्रिंट सेंसर का इस्तेमाल करती है

आपको इनकी ज़रूरत होगी

  • इनमें से कोई एक डिवाइस:
    • Android डिवाइस, जिसमें बायोमेट्रिक सेंसर हो
    • iOS 14 या उसके बाद के वर्शन पर, iPhone या iPad पर Touch ID या Face ID की सुविधा
    • macOS Big Sur या इसके बाद के वर्शन पर, Touch ID वाला MacBook Pro या Air
    • Windows 10 19H1 या उसके बाद के वर्शन के साथ, Windows Hello सेट अप करना
  • इनमें से कोई एक ब्राउज़र:
    • Google Chrome 67 या इसके बाद का वर्शन
    • Microsoft Edge 85 या इसके बाद का वर्शन
    • Safari 14 या उसके बाद का वर्शन

2. सेट अप करें

इस कोडलैब में आप ग्लिच नाम की सेवा का इस्तेमाल करेंगे. JavaScript वाले क्लाइंट और सर्वर साइड कोड में बदलाव करने के साथ ही उन्हें तुरंत डिप्लॉय किया जा सकता है.

https://glitch.com/edit/#!/webauthn-codelab-start पर जाएं.

देखें कि यह कैसे काम करता है

वेबसाइट की शुरुआती स्थिति देखने के लिए, यह तरीका अपनाएं:

  1. लाइव वेबसाइट देखने के लिए, 62bb7a6aac381af8.png नई विंडो में दिखाएं पर क्लिक करें.
  2. अपनी पसंद का उपयोगकर्ता नाम डालें और आगे बढ़ें पर क्लिक करें.
  3. पासवर्ड डालें और साइन इन करें पर क्लिक करें.

पासवर्ड को अनदेखा कर दिया गया है, लेकिन आप अब भी प्रमाणित हैं. आप होम पेज पर पहुंचते हैं.

  1. फिर से पुष्टि करने की कोशिश करें पर क्लिक करें और दूसरा, तीसरा, और चौथा चरण दोहराएं.
  2. साइन आउट करें पर क्लिक करें.

ध्यान दें कि आपको हर बार साइन इन करने की कोशिश करते समय पासवर्ड डालना होगा. यह किसी उपयोगकर्ता को वेबसाइट के किसी अहम सेक्शन को ऐक्सेस करने से पहले, फिर से पुष्टि करने वाले एम्युलेट करता है.

कोड को रीमिक्स करें

  1. WebAuthn / FIDO2 एपीआई कोडलैब (कोड बनाना सीखना) पर जाएं.
  2. प्रोजेक्ट को फ़ोर्क करने के लिए, अपने प्रोजेक्ट के नाम; Remix प्रोजेक्ट 306122647ce93305.png पर क्लिक करें. इसके बाद, नए यूआरएल पर अपने वर्शन के साथ जारी रखें.

8d42bd24f0fd185c.png

3. फ़िंगरप्रिंट को क्रेडेंशियल से रजिस्टर करें

आपको यूवीपीए से जनरेट किया गया क्रेडेंशियल रजिस्टर करना होगा. यह एक ऐसा पुष्टि करने वाला होता है जो डिवाइस में पहले से मौजूद होता है और उपयोगकर्ता की पहचान की पुष्टि करता है. आम तौर पर, इसे उपयोगकर्ता के डिवाइस के हिसाब से, फ़िंगरप्रिंट सेंसर के तौर पर देखा जाता है.

आप इस सुविधा को /home पेज पर जोड़ते हैं:

260aab9f1a2587a7.png

registerCredential() फ़ंक्शन बनाएं

एक registerCredential() फ़ंक्शन बनाएं, जिससे एक नया क्रेडेंशियल रजिस्टर हो.

public/client.js

export const registerCredential = async () => {

};

सर्वर एंडपॉइंट से चुनौती और अन्य विकल्प पाएं

उपयोगकर्ता को नया क्रेडेंशियल रजिस्टर करने के लिए कहें, इससे पहले यह अनुरोध करें कि सर्वर, WebAuthn में पास होने के लिए पैरामीटर भी भेजे. इसमें एक चैलेंज भी शामिल है. सबसे अच्छी बात यह है कि आपके पास पहले से ही ऐसा सर्वर एंडपॉइंट है जो इस तरह के पैरामीटर के साथ जवाब देता है.

registerCredential() में यह कोड जोड़ें.

public/client.js

const opts = {
  attestation: 'none',
  authenticatorSelection: {
    authenticatorAttachment: 'platform',
    userVerification: 'required',
    requireResidentKey: false
  }
};

const options = await _fetch('/auth/registerRequest', opts);

सर्वर और क्लाइंट के बीच का प्रोटोकॉल, WebAuthn की खास बातों का हिस्सा नहीं है. हालांकि, इस कोडलैब को WebAuthn की खास बातों और आपके सर्वर से पास किए जाने वाले JSON ऑब्जेक्ट के मुताबिक बनाया गया है, ताकि यह आपके लिए आसान और PublicKeyCredentialCreationOptions बन सके. इस टेबल में ऐसे ज़रूरी पैरामीटर हैं जिन्हें आप सर्वर को भेज सकते हैं. साथ ही, इन कार्रवाइयों के बारे में बता सकते हैं:

पैरामीटर

विवरण

attestation

प्रमाणित करने से जुड़े मैसेज की प्राथमिकता—none, indirect या direct. अगर आपको इसकी ज़रूरत नहीं है, तो none चुनें.

excludeCredentials

PublicKeyCredentialDescriptor की कैटगरी, ताकि पुष्टि करने वाले डुप्लीकेट ऐप्लिकेशन बनाने से बच सकें.

authenticatorSelection

authenticatorAttachment

उपलब्ध Authenticator को फ़िल्टर करें. अगर आप डिवाइस से कोई पुष्टि करने वाले को जोड़ना चाहते हैं, तो &kot;platform&कोटेशन; का इस्तेमाल करें. रोमिंग की पुष्टि करने वाले प्रोग्राम के लिए, &कोटेशन का इस्तेमाल करें;&brt;;cross-platform&कोटेशन;.

userVerification

तय करें कि पुष्टि करने वाले स्थानीय उपयोगकर्ता की पुष्टि &?"required" या &कोटेशनdiscouraged है;. अगर आप फ़िंगरप्रिंट या स्क्रीन-लॉक की पुष्टि करना चाहते हैं, तो &requiredका इस्तेमाल करें;required.

requireResidentKey

अगर बनाया गया क्रेडेंशियल, आने वाले समय के खाता पिकर UX के लिए उपलब्ध होना चाहिए, तो true का इस्तेमाल करें.

इन विकल्पों के बारे में ज़्यादा जानने के लिए 5.4 देखें. क्रेडेंशियल बनाने के विकल्प (शब्दावली (PublicKeyCredentialCreationOptions).

नीचे ऐसे विकल्प दिए गए हैं जो आपको सर्वर से मिलते हैं.

{
  "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"
  }
}

कोई क्रेडेंशियल बनाएं

  1. इन विकल्पों को एचटीटीपी प्रोटोकॉल की मदद से कोड में बदलने के लिए डिलीवर किया जाता है. इसलिए, कुछ पैरामीटर को वापस बाइनरी में बदलें, खास तौर पर, user.id, challenge, और excludeCredentials अरे में शामिल id के इंस्टेंस:

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);
  }
}
  1. नया क्रेडेंशियल बनाने के लिए, navigator.credentials.create() के तरीके को कॉल करें.

इस कॉल के साथ, ब्राउज़र, पुष्टि करने वाले व्यक्ति से इंटरैक्ट करता है और यूवीपीए के साथ उपयोगकर्ता की पहचान की पुष्टि करने की कोशिश करता है.

public/client.js

const cred = await navigator.credentials.create({
  publicKey: options,
});

जब उपयोगकर्ता अपनी पहचान की पुष्टि कर लेगा, तब आपको एक क्रेडेंशियल ऑब्जेक्ट मिलेगा. आप इसे सर्वर पर भेज सकते हैं. साथ ही, पुष्टि करने वाले प्रोग्राम में रजिस्टर कर सकते हैं.

क्रेडेंशियल को सर्वर एंडपॉइंट पर रजिस्टर करें

यहां क्रेडेंशियल का एक उदाहरण दिया गया है, जो आपको मिला होना चाहिए.

{
  "id": "...",
  "rawId": "...",
  "type": "public-key",
  "response": {
    "clientDataJSON": "...",
    "attestationObject": "..."
  }
}
  1. जैसे जब आपको क्रेडेंशियल रजिस्टर करने के लिए विकल्प ऑब्जेक्ट मिलता है, तो क्रेडेंशियल के बाइनरी पैरामीटर को कोड में बदलें, ताकि उन्हें सर्वर पर स्ट्रिंग के रूप में डिलीवर किया जा सके:

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,
  };
}
  1. क्रेडेंशियल आईडी को स्थानीय रूप से स्टोर करें, ताकि उपयोगकर्ता के वापस आने पर पुष्टि करने के लिए आप इसका इस्तेमाल कर सकें:

public/client.js

localStorage.setItem(`credId`, credential.id);
  1. ऑब्जेक्ट को सर्वर पर भेजें और अगर यह HTTP code 200 दिखाता है, तो नए क्रेडेंशियल को सही के तौर पर रजिस्टर करें.

public/client.js

return await _fetch('/auth/registerResponse' , credential);

अब आपके पास पूरा registerCredential() फ़ंक्शन है!

इस सेक्शन के लिए फ़ाइनल कोड

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. रजिस्टर करने, पाने, और हटाने के लिए, यूज़र इंटरफ़ेस (यूआई) बनाएं

यूआरएल को हटाने के लिए, रजिस्टर किए गए क्रेडेंशियल और बटन की सूची होना अच्छी बात है.

9b5b5ae4a7b316bd.png

बिल्ड यूज़र इंटरफ़ेस (यूआई) प्लेसहोल्डर

क्रेडेंशियल की सूची बनाने के लिए यूज़र इंटरफ़ेस (यूआई) और नया क्रेडेंशियल रजिस्टर करने के लिए बटन जोड़ें. यह सुविधा उपलब्ध है या नहीं, इसके आधार पर आप hidden क्लास को चेतावनी के मैसेज से या नया क्रेडेंशियल रजिस्टर करने के लिए बटन से हटा सकते हैं. ul#list रजिस्टर किए गए क्रेडेंशियल की सूची जोड़ने के लिए प्लेसहोल्डर है.

view/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>

सुविधा की पहचान और यूवीपीए की उपलब्धता

यूवीपीए की उपलब्धता देखने के लिए, यह तरीका अपनाएं:

  1. WebAuthn उपलब्ध है या नहीं, यह देखने के लिए window.PublicKeyCredential की जांच करें.
  2. यूवीपीए उपलब्ध है या नहीं, यह देखने के लिए PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() को कॉल करें . अगर वे उपलब्ध हैं#39;आप नया क्रेडेंशियल रजिस्टर करने के लिए बटन दिखाते हैं. अगर इनमें से कोई भी विकल्प मौजूद न हो, तो आपको चेतावनी वाला मैसेज दिखेगा.

view/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');
}

क्रेडेंशियल की सूची पाना और दिखाना

  1. getCredentials() फ़ंक्शन बनाएं, ताकि आप रजिस्टर किए गए क्रेडेंशियल पा सकें. साथ ही, उन्हें सूची में दिखा सकें. सबसे अच्छी बात यह है कि आपके पास /auth/getKeys सर्वर पर एक आसान एंडपॉइंट है, जिससे आप साइन इन किए हुए उपयोगकर्ता के लिए रजिस्टर किए गए क्रेडेंशियल पा सकते हैं.

लौटाए गए JSON में, क्रेडेंशियल की जानकारी शामिल है, जैसे कि id और publicKey. आप उपयोगकर्ताओं को दिखाने के लिए HTML बना सकते हैं.

view/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);
};
  1. जैसे ही उपयोगकर्ता /home पेज पर पहुंचे, getCredentials() को उपलब्ध क्रेडेंशियल दिखाने के लिए कहें.

view/home.html

getCredentials();

क्रेडेंशियल हटाएं

क्रेडेंशियल की सूची में, आपने हर क्रेडेंशियल को हटाने के लिए एक बटन जोड़ा है. उन्हें हटाने के लिए, आप credId क्वेरी पैरामीटर के साथ /auth/removeKey को अनुरोध भेज सकते हैं.

public/client.js

export const unregisterCredential = async (credId) => {
  localStorage.removeItem('credId');
  return _fetch(`/auth/removeKey?credId=${encodeURIComponent(credId)}`);
};
  1. मौजूदा import स्टेटमेंट में unregisterCredential जोड़ें.

view/home.html

import { _fetch, unregisterCredential } from '/client.js';
  1. उपयोगकर्ता के हटाएं पर क्लिक करने पर, एक फ़ंक्शन जोड़ें.

view/home.html

const removeCredential = async e => {
  try {
    await unregisterCredential(e.target.id);
    getCredentials();
  } catch (e) {
    alert(e);
  }
};

क्रेडेंशियल रजिस्टर करें

जब उपयोगकर्ता क्रेडेंशियल जोड़ें पर क्लिक करता है, तब नया क्रेडेंशियल रजिस्टर करने के लिए, आप registerCredential() को कॉल कर सकते हैं.

  1. मौजूदा import स्टेटमेंट में registerCredential जोड़ें.

view/home.html

import { _fetch, registerCredential, unregisterCredential } from '/client.js';
  1. registerCredential() को navigator.credentials.create() के विकल्पों के साथ इस्तेमाल करें.

रजिस्ट्रेशन के बाद getCredentials() को कॉल करके क्रेडेंशियल सूची को रिन्यू करना न भूलें.

view/home.html

register.addEventListener('click', e => {
  registerCredential().then(user => {
    getCredentials();
  }).catch(e => alert(e));
});

अब आप नया क्रेडेंशियल रजिस्टर कर सकते हैं और इसके बारे में जानकारी दिखा सकते हैं. आप इसे अपनी लाइव वेबसाइट पर आज़मा सकते हैं.

इस सेक्शन के लिए फ़ाइनल कोड

view/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. फ़िंगरप्रिंट की मदद से, उपयोगकर्ता की पुष्टि करना

अब आपके पास क्रेडेंशियल क्रेडेंशियल रजिस्टर है और उपयोगकर्ता को पुष्टि करने के लिए इस्तेमाल किया जा सकता है. अब आप वेबसाइट में, फिर से पुष्टि करने का फ़ंक्शन जोड़ सकते हैं. उपयोगकर्ता का अनुभव यहां दिया गया है:

अगर कोई उपयोगकर्ता /reauth पेज पर आता है, तो उसे बायोमेट्रिक पुष्टि हो जाने पर पुष्टि करें बटन दिखता है. फ़िंगरप्रिंट (यूपीए) के ज़रिए पुष्टि करने की प्रक्रिया तब शुरू होती है, जब वे पुष्टि करें पर टैप करते हैं, पुष्टि हो जाती है, और /home पेज पर पहुंच जाते हैं. अगर बायोमेट्रिक की पुष्टि नहीं हो पाती या बायोमेट्रिक की मदद से पुष्टि नहीं हो पाती, तो यूज़र इंटरफ़ेस (यूआई) मौजूदा पासवर्ड फ़ॉर्म का इस्तेमाल करता है.

b7770c4e7475b075.png

authenticate() फ़ंक्शन बनाएं

authenticate() नाम का एक फ़ंक्शन बनाएं जो फ़िंगरप्रिंट की मदद से, उपयोगकर्ता की पहचान की पुष्टि करता है. आप JavaScript कोड यहां जोड़ते हैं:

public/client.js

export const authenticate = async () => {

};

सर्वर एंडपॉइंट से चुनौती और अन्य विकल्प पाएं

  1. पुष्टि करने से पहले, देखें कि उपयोगकर्ता के पास कोई क्रेडेंशियल क्रेडेंशियल सेव है या नहीं. अगर ऐसा है, तो उसे क्वेरी पैरामीटर के तौर पर सेट करें.

जब आप अन्य विकल्पों के साथ क्रेडेंशियल आईडी देते हैं, तो सर्वर काम का allowCredentials उपलब्ध करा सकता है. इससे उपयोगकर्ता की पुष्टि भरोसेमंद हो जाती है.

public/client.js

const opts = {};

let url = '/auth/signinRequest';
const credId = localStorage.getItem(`credId`);
if (credId) {
  url += `?credId=${encodeURIComponent(credId)}`;
}
  1. उपयोगकर्ता से पुष्टि करने से पहले, सर्वर को चुनौती और दूसरे पैरामीटर वापस भेजने के लिए कहें. सर्वर को POST अनुरोध भेजने के लिए, तर्क के तौर पर opts के साथ _fetch() को कॉल करें.

public/client.js

const options = await _fetch(url, opts);

यहां कुछ उदाहरण दिए गए हैं, जो आपको मिलने चाहिए (PublicKeyCredentialRequestOptions के साथ अलाइन होता है).

{
  "challenge": "...",
  "timeout": 1800000,
  "rpId": "webauthn-codelab.glitch.me",
  "userVerification": "required",
  "allowCredentials": [
    {
      "id": "...",
      "type": "public-key",
      "transports": [
        "internal"
      ]
    }
  ]
}

सबसे ज़रूरी विकल्प allowCredentials है. जब आपको सर्वर से विकल्प मिलते हैं, तो allowCredentials को कैटगरी या खाली खाली कैटगरी में से एक ऑब्जेक्ट होना चाहिए. यह इस बात पर निर्भर करता है कि सर्वर पैरामीटर पर क्वेरी पैरामीटर में आईडी के साथ क्रेडेंशियल मिला है या नहीं.

  1. जब allowCredentials एक खाली अरे हो, तो null के साथ प्रॉमिस रिज़ॉल्व करें, ताकि यूज़र इंटरफ़ेस (यूआई) पासवर्ड मांगने के लिए वापस आ जाए.
if (options.allowCredentials.length === 0) {
  console.info('No registered credentials found.');
  return Promise.resolve(null);
}

उपयोगकर्ता की स्थानीय तौर पर पुष्टि करें और क्रेडेंशियल पाएं

  1. इन विकल्पों को एचटीटीपी प्रोटोकॉल की मदद से डिलीवर करने के लिए, कोड में बदला गया होता है. इसलिए, कुछ पैरामीटर बाइनरी में बदलें, खास तौर पर challenge और allowCredentials श्रेणी में शामिल id के इंस्टेंस:

public/client.js

options.challenge = base64url.decode(options.challenge);

for (let cred of options.allowCredentials) {
  cred.id = base64url.decode(cred.id);
}
  1. यूवीपीए की मदद से उपयोगकर्ता की पहचान की पुष्टि करने के लिए, navigator.credentials.get() का तरीका इस्तेमाल करें.

public/client.js

const cred = await navigator.credentials.get({
  publicKey: options
});

जब उपयोगकर्ता अपनी पहचान की पुष्टि कर लेगा, तब आपको क्रेडेंशियल वाला ऑब्जेक्ट मिलेगा जिसे आप सर्वर पर भेज सकते हैं. साथ ही, उपयोगकर्ता की पुष्टि भी कर सकते हैं.

क्रेडेंशियल की पुष्टि करें

यहां एक PublicKeyCredential ऑब्जेक्ट (response का AuthenticatorAssertionResponse) उदाहरण दिया गया है, जो आपको मिला होना चाहिए:

{
  "id": "...",
  "type": "public-key",
  "rawId": "...",
  "response": {
    "clientDataJSON": "...",
    "authenticatorData": "...",
    "signature": "...",
    "userHandle": ""
  }
}
  1. क्रेडेंशियल के बाइनरी पैरामीटर को कोड में बदलें, ताकि उन्हें सर्वर पर स्ट्रिंग के रूप में डिलीवर किया जा सके:

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,
  };
}
  1. ऑब्जेक्ट को सर्वर पर भेजें और अगर यह HTTP code 200 दिखाता है, तो उपयोगकर्ता को सही तरीके से साइन इन करने के तौर पर देखें:

public/client.js

return await _fetch(`/auth/signinResponse`, credential);

अब आपके पास पूरा authentication() फ़ंक्शन है!

इस सेक्शन के लिए फ़ाइनल कोड

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. फिर से पुष्टि करने की सुविधा चालू करें

बिल्ड यूज़र इंटरफ़ेस (यूआई)

उपयोगकर्ता के वापस आने पर, आप चाहते हैं कि वह उन्हें आसानी से और सुरक्षित तौर पर फिर से पुष्टि करे. यहां बायोमेट्रिक पुष्टि की सुविधा काम करती है. हालांकि, कुछ मामलों में बायोमेट्रिक पुष्टि की सुविधा काम नहीं कर सकती:

  • यूवीपीए उपलब्ध नहीं है.
  • उपयोगकर्ता ने अपने डिवाइस पर अभी तक कोई क्रेडेंशियल रजिस्टर नहीं किया है.
  • डिवाइस की मेमोरी हटा दी गई है और डिवाइस अब क्रेडेंशियल आईडी को याद नहीं रखता है.
  • उपयोगकर्ता किसी वजह से अपनी पहचान की पुष्टि नहीं कर पा रहा है. जैसे, जब उपयोगकर्ता की उंगली गीली हो या उसने मास्क पहन रखा हो.

इसलिए, यह हमेशा अहम होता है कि फ़ॉलबैक के तौर पर साइन इन के दूसरे विकल्प दिए जाएं. इस कोडलैब में, फ़ॉर्म के आधार पर पासवर्ड इस्तेमाल किया जा सकता है.

19599900145054

  1. पुष्टि करने का बटन दिखाने के लिए, यूज़र इंटरफ़ेस (यूआई) जोड़ें. इससे, पासवर्ड फ़ॉर्म के अलावा, बायोमेट्रिक पुष्टि करने वाला प्रोग्राम भी शुरू होगा.

उपयोगकर्ता की # स्थिति के हिसाब से, hidden क्लास को चुनिंदा तरीके से दिखाने और छिपाने के लिए, इसका इस्तेमाल करें.

view/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>
  1. फ़ॉर्म में class="hidden" जोड़ें:

view/reauth.html

<form id="form" method="POST" action="/auth/password" class="hidden">

सुविधा की पहचान और यूवीपीए की उपलब्धता

इनमें से कोई एक शर्त पूरी होने पर, उपयोगकर्ताओं को पासवर्ड से साइन इन करना चाहिए:

  • WebAuthn उपलब्ध नहीं है.
  • यूवीपीए उपलब्ध नहीं है.
  • इस यूवीपीए के लिए क्रेडेंशियल आईडी को नहीं खोजा जा सकता.

पुष्टि करने वाले बटन को चुनिंदा तरीके से दिखाएं या छिपाएं:

view/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');
}

पासवर्ड फ़ॉर्म पर वापस जाएं

उपयोगकर्ता के पास पासवर्ड से साइन इन करने का विकल्प भी होना चाहिए.

जब उपयोगकर्ता पासवर्ड से साइन इन करें पर क्लिक करे, तो पासवर्ड फ़ॉर्म दिखाएं और पुष्टि करने वाले बटन को छिपाएं:.

view/reauth.html

const cancel = document.querySelector('#cancel');
cancel.addEventListener('click', e => {
  form.classList.remove('hidden');
  document
    .querySelector('#uvpa_available')
    .classList.add('hidden');
});

c4a82800889f078c.png

बायोमेट्रिक पुष्टि करें

आखिर में, बायोमेट्रिक की पुष्टि करने की सुविधा चालू करें.

  1. मौजूदा import स्टेटमेंट में authenticate जोड़ें:

view/reauth.html

import { _fetch, authenticate } from '/client.js';
  1. बायोमेट्रिक पुष्टि करने के लिए, authenticate() को तब चालू करें, जब उपयोगकर्ता पुष्टि करें पर टैप करे.

पक्का करें कि बायोमेट्रिक पुष्टि करने में कोई गड़बड़ी हुई है या नहीं.

view/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');
  });        
});

इस सेक्शन के लिए फ़ाइनल कोड

view/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. बधाई हो!

आपने यह कोडलैब पूरा कर लिया है!

ज़्यादा जानें

मदद के लिए, FIDO Alliance के YouTube चैनल पर को धन्यवाद.