首頁  >  文章  >  web前端  >  使用 WebAuthn 在 Angular 應用程式中整合指紋和 Face ID 驗證:逐步指南

使用 WebAuthn 在 Angular 應用程式中整合指紋和 Face ID 驗證:逐步指南

王林
王林原創
2024-09-05 19:00:21790瀏覽

說實話,我們都希望能夠使用指紋或 Face ID 登入網站,就像在行動應用程式上一樣,對吧?好吧,多虧了網路生物辨識技術,這個夢想不再那麼遙不可及。想像一下,拋棄那些又長又複雜的密碼,只需使用我們的指紋或臉部登入我們最喜歡的網站。聽起來很酷,不是嗎?

Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

由 WebAuthn 提供支援的網路生物辨識技術使這一切成為可能。這是一個非常簡單的東西的奇特名稱:使用與手機指紋感應器或臉部識別相同的安全性來驗證我們的身份,但直接在我們的網路瀏覽器中進行。不再擔心密碼洩漏或被盜——只需快速掃描,我們就可以了。

在本教程中,我們將親自動手將指紋和 Face ID 登入整合到我們的 Angular 應用程式中。我們將介紹基本知識,例如 WebAuthn API 的工作原理以及我們需要在後端執行哪些操作以確保一切安全和順利。這比您想像的要容易,到最後,我們將為未來的身份驗證做好所有設定。所以,讓我們深入研究,讓登入變得輕而易舉!

了解 WebAuthn:Angular 應用程式中指紋和人臉辨識的基礎知識

Integrate Fingerprint and Face ID Authentication in Your Angular App Using WebAuthn: A Step-by-Step Guide

好吧,在我們進入程式碼之前,讓我們快速了解一下 WebAuthn 的意思。將 WebAuthn 視為橋樑,將我們的應用程式與我們喜歡的手機上的生物識別功能(如指紋和 Face ID)連接起來,就在我們的瀏覽器中。它使用公鑰加密技術來驗證用戶身份,這意味著不再儲存駭客可以輕鬆竊取的普通舊密碼。相反,我們談論的是安全生成的金鑰,它使我們的登入既安全又無縫。

關鍵對象及其作用

為了讓事情順利進行,我們需要了解 WebAuthn 遊戲中的幾個關鍵角色:PublicKeyCredentialCreationOptions 和 PublicKeyCredentialRequestOptions。不要讓長名稱嚇到您——它們只是告訴瀏覽器我們要如何註冊和驗證用戶身份的奇特方式。

1. 公鑰憑證建立選項

這是我們設定新使用者憑證時的首選物件。它包括:

  • 挑戰:伺服器產生的唯一隨機值,以確保回應是最新的且無法重複使用。
  • rp:代表依賴方(我們的應用程式),包含應用程式名稱和 ID 等詳細資訊。
  • 使用者:有關使用者的信息,例如唯一 ID、使用者名稱和顯示名稱。
  • pubKeyCredParams:我們允許的公鑰演算法清單。
  • authenticatorSelection:幫助我們根據附件類型(平台或跨平台)和使用者驗證等級等選擇正確的身份驗證器類型。

2. 公鑰憑證請求選項

當需要驗證我們的使用者時,這個物件就會成為人們關注的焦點。它包括:

  • 挑戰:就像以前一樣,這確保我們的身分驗證請求是新鮮且獨特的。
  • allowCredentials:指定允許使用者使用哪些憑證。
  • userVerification:指示是否需要使用者驗證(如指紋掃描)。

有了這些對象,我們的 Angular 應用程式將能夠指導用戶註冊其生物識別數據並快速、安全地進行身份驗證。接下來,我們將進入程式碼,看看如何在我們的應用程式中實現這個魔法!

設定 Angular 應用程式

在本節中,我們將指導您使用 WebAuthn 設定具有生物辨識驗證的 Angular 應用程式。我們將專注於使用指紋和 Face ID,所以讓我們動手吧!

第 1 步:設定我們的 Angular 項目

首先,讓我們建立一個新的 Angular 專案。開啟終端機並輸入以下命令:

ng new web-biometrics-demo
cd web-biometrics-demo
ng serve

這會設定一個基本的 Angular 應用程序,運行 ngserve 將在 http://localhost:4200/ 上啟動您的應用程式。您應該會看到預設的 Angular 歡迎頁面。現在,我們已準備好整合 WebAuthn 進行生物辨識身分驗證。

第 2 步:建立 WebAuthn 服務

我們需要 Angular 中的一項服務來管理我們所有的 WebAuthn 功能,包括使用生物辨識技術進行註冊和驗證。讓我們透過執行以下命令來建立此服務:

ng generate service services/webauthn

Now, open webauthn.service.ts and add the following code:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class WebAuthnService {

  constructor() { }

  // Generates a random buffer to use as a challenge, which is a unique value needed for security
  private generateRandomBuffer(length: number): Uint8Array {
    const randomBuffer = new Uint8Array(length);
    window.crypto.getRandomValues(randomBuffer); // Fills the buffer with cryptographically secure random values
    return randomBuffer;
  }

  // Registers a new credential (like a fingerprint or Face ID) for the user
  async register() {
    // Generate a unique challenge for the registration process
    const challenge = this.generateRandomBuffer(32);

    // PublicKeyCredentialCreationOptions is the core object needed for registration
    const publicKey: PublicKeyCredentialCreationOptions = {
      challenge: challenge, // A random value generated by the server to ensure the request is fresh and unique
      rp: { // Relying Party (your app) information
        name: "OurAwesomeApp" // Display name of your app
      },
      user: { // User information
        id: this.generateRandomBuffer(16), // A unique identifier for the user
        name: "user@example.com", // User's email or username
        displayName: "User Example" // A friendly name for the user
      },
      pubKeyCredParams: [{ // Array of acceptable public key algorithms
        type: "public-key",
        alg: -7  // Represents the ES256 algorithm (Elliptic Curve Digital Signature Algorithm)
      }],
      authenticatorSelection: { // Criteria for selecting the appropriate authenticator
        authenticatorAttachment: "platform", // Ensures we use the device's built-in biometric authenticator like Touch ID or Face ID
        userVerification: "required" // Requires user verification (e.g., fingerprint or face scan)
      },
      timeout: 60000, // Timeout for the registration operation in milliseconds
      attestation: "direct" // Attestation provides proof of the authenticator's properties and is sent back to the server
    };

    try {
      // This will prompt the user to register their biometric credential
      const credential = await navigator.credentials.create({ publicKey }) as PublicKeyCredential;
      this.storeCredential(credential, challenge); // Store the credential details locally for demo purposes
      console.log("Registration successful!", credential);
      return credential; // Return the credential object containing the user's public key and other details
    } catch (err) {
      console.error("Registration failed:", err);
      throw err; // Handle any errors that occur during registration
    }
  }

  // Authenticates the user with stored credentials (like a fingerprint or Face ID)
  async authenticate() {
    const storedCredential = this.getStoredCredential(); // Retrieve stored credential information
    if (!storedCredential) {
      throw new Error("No stored credential found. Please register first."); // Error if no credentials are found
    }

    // PublicKeyCredentialRequestOptions is used to prompt the user to authenticate
    const publicKey: PublicKeyCredentialRequestOptions = {
      challenge: new Uint8Array(storedCredential.challenge), // A new challenge to ensure the request is fresh and unique
      allowCredentials: [{ // Specifies which credentials can be used for authentication
        id: new Uint8Array(storedCredential.rawId), // The ID of the credential to use
        type: "public-key"
      }],
      userVerification: "required", // Requires user verification (e.g., fingerprint or face scan)
      timeout: 60000 // Timeout for the authentication operation in milliseconds
    };

    try {
      // This will prompt the user to authenticate using their registered biometric credential
      const credential = await navigator.credentials.get({ publicKey }) as PublicKeyCredential;
      console.log("Authentication successful!", credential);
      return credential; // Return the credential object with authentication details
    } catch (err) {
      console.error("Authentication failed:", err);
      throw err; // Handle any errors that occur during authentication
    }
  }

  // Stores credential data in localStorage (for demo purposes only; this should be handled securely in production)
  private storeCredential(credential: PublicKeyCredential, challenge: Uint8Array) {
    const credentialData = {
      rawId: Array.from(new Uint8Array(credential.rawId)), // Converts the raw ID to an array for storage
      challenge: Array.from(challenge) // Converts the challenge to an array for storage
    };
    localStorage.setItem('webauthn_credential', JSON.stringify(credentialData)); // Store the data as a JSON string
  }

  // Retrieves stored credential data from localStorage
  private getStoredCredential(): any {
    const storedCredential = localStorage.getItem('webauthn_credential');
    return storedCredential ? JSON.parse(storedCredential) : null; // Parse the stored JSON back into an object
  }
}

What’s Happening in the Code?

  • generateRandomBuffer: Creates a random buffer that serves as a challenge to ensure each authentication or registration request is unique.

  • register: This method sets up the biometric registration process. It uses PublicKeyCredentialCreationOptions to define parameters like the challenge, relying party (your app), user information, and acceptable public key algorithms. When navigator.credentials.create() is called, the browser prompts the user to register their biometric data.

  • authenticate: This method handles user authentication with biometrics. It uses PublicKeyCredentialRequestOptions to define the authentication challenge and credentials that can be used. The method prompts the user to authenticate with their registered biometrics.

  • storeCredential and getStoredCredential: These methods handle storing and retrieving credentials in localStorage for demonstration purposes.

    In a real-world app, you’d securely store this information on your backend.

Step 3: Building the UI

Now, let’s create a basic UI with buttons to trigger the registration and login functions. This UI will provide feedback based on whether the registration or login was successful.

Open app.component.ts and replace the content with the following:

import { Component } from '@angular/core';
import { WebAuthnService } from './services/webauthn.service';

@Component({
  selector: 'app-root',
  template: `
    <div class="auth-container">
      <h1>Web Biometrics in Angular</h1>
      <button (click)="register()">Register with Fingerprint</button>
      <button (click)="login()">Login with Face ID</button>
      <p *ngIf="message" [ngClass]="{'success': isSuccess, 'error': !isSuccess}">{{ message }}</p>
    </div>
  `,
  styles: [`
    .auth-container {
      text-align: center;
      padding: 50px;
    }
    .success {
      color: green;
    }
    .error {
      color: red;
    }
    button {
      margin: 10px;
      padding: 10px 20px;
      font-size: 16px;
    }
    p {
      margin: 10px;
      font-size: 16px;
    }
  `]
})
export class AppComponent {
  message: string | null = null; // Message to display feedback to the user
  isSuccess: boolean = false; // Indicates if the last action was successful

  constructor(private webAuthnService: WebAuthnService) { }

  // Trigger registration process and update the UI based on the outcome
  async register() {
    try {
      await this.webAuthnService.register();
      this.message = "Registration successful!"; // Success message if registration works
      this.isSuccess = true;
    } catch (err) {
      this.message = "Registration failed. Please try again."; // Error message if something goes wrong
      this.isSuccess = false;
    }
  }

  // Trigger authentication process and update the UI based on the outcome
  async login() {
    try {
      await this.webAuthnService.authenticate();
      this.message = "Authentication successful!"; // Success message if authentication works
      this.isSuccess = true;
    } catch (err) {
      this.message = "Authentication failed. Please try again."; // Error message if something goes wrong
      this.isSuccess = false;
    }
  }
}

What’s Happening in the Component?

register and login methods: These methods call the respective register and authenticate methods from the WebAuthnService. If successful, a success message is displayed; otherwise, an error message is shown.

Template and Styling: The template includes buttons to trigger registration and login, and it displays messages to the user based on the operation's outcome. The buttons are styled for simplicity.

That’s it! We’ve built a basic Angular app with WebAuthn-based biometric authentication, supporting fingerprints and Face ID. This setup captures the core concepts and lays a foundation that can be expanded with additional features and security measures for a production environment.

Backend Considerations

When implementing biometric authentication like fingerprints or Face ID in web applications using WebAuthn, the backend plays a crucial role in managing the security and flow of data. Here’s a breakdown of how the backend processes work in theory, focusing on registration and login functionalities.

Registration: Sign-up

1. User Registration Flow:

  • User Data Capture: During registration, the user provides basic credentials, such as an email and password. If biometric data is also being registered, this is captured as part of the WebAuthn response.

  • Password Hashing: For security, passwords are never stored in plain text. Instead, they are hashed using a library like bcrypt before being stored in the database.

  • Storing WebAuthn Credentials:

    • Challenge Handling: The server sends a challenge during the registration process, which is a randomly generated value to prevent replay attacks.
    • Response Validation: When the client responds with the WebAuthn data, it includes clientDataJSON and attestationObject that need to be decoded and verified.
    • Credential Storage: After validation, key data from the response—like the webauthnId (a unique identifier for the credential) and the publicKey (used to verify future authentications)—are stored in the database alongside the user record.

2. Backend Code Responsibilities:

  • The backend uses libraries like cbor to decode binary data formats from the WebAuthn response, extracting necessary elements like the public key and authenticator data.

  • It ensures that the challenge from the initial registration request matches what is returned in the WebAuthn response to verify the authenticity of the registration.

  • If the WebAuthn response passes all checks, the credentials are saved in the database, linked to the user account.

Login

1. User Login Flow:

  • Challenge Generation: Similar to registration, the server generates a challenge that must be responded to by the client’s authenticator during login.

  • Validating the WebAuthn Response:

    • The client sends back a PublicKeyCredentialRequestOptions object containing the response to the challenge.
    • The backend decodes and verifies this response, ensuring that the challenge and the credentials match what is stored in the database.
  • Credential Verification:

    • The public key stored during registration is used to verify the signature in the login response.
    • If the credentials match, the backend allows the login and generates an authentication token (like a JWT) for the session.

Error Handling:

  • Mismatch or Invalid Response: If the challenge response does not match the expected values, or if the WebAuthn credentials do not verify correctly, the backend responds with an error, preventing unauthorized access.

  • Fallback to Password: If WebAuthn fails or is unavailable, the system can revert to traditional password verification, ensuring users can still access their accounts.

Security Considerations

  • Data Integrity: The integrity of WebAuthn credentials is critical. Any modification in storage or transmission would cause verification to fail, thereby securing the authentication process.

  • Challenge Nonces: The use of unique, time-limited challenges ensures that responses cannot be reused, protecting against replay attacks.

  • Public Key Storage: Storing only public keys (which cannot be used to impersonate the user) enhances security, as private keys remain on the client device.

By following these principles, the backend effectively manages biometric authentication, ensuring a secure, seamless experience for users wanting to use features like fingerprint or Face ID in their Angular apps.

In Summary

In this tutorial, we walked into integrating biometric authentication with Angular using WebAuthn. We covered the essentials, from understanding key WebAuthn objects like PublicKeyCredentialCreationOptions and PublicKeyCredentialRequestOptions to setting up Angular services and UI components for a smooth registration and login process. We also discussed the backend considerations necessary for handling biometric authentication securely.

For those eager to see WebAuthn in action, I have provided a demo and a repository with a complete implementation. You can check out the demo here and explore the source code on GitHub at this repository.

Embracing biometric authentication not only enhances security but also simplifies the user experience, paving the way for a future where logging in is as easy as a fingerprint scan or a quick face recognition. As you integrate these features into your Angular apps, you'll be contributing to a more secure and user-friendly web. Happy coding!

以上是使用 WebAuthn 在 Angular 應用程式中整合指紋和 Face ID 驗證:逐步指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
上一篇:功能下一篇:功能