說實話,我們都希望能夠使用指紋或 Face ID 登入網站,就像在行動應用程式上一樣,對吧?好吧,多虧了網路生物辨識技術,這個夢想不再那麼遙不可及。想像一下,拋棄那些又長又複雜的密碼,只需使用我們的指紋或臉部登入我們最喜歡的網站。聽起來很酷,不是嗎?
由 WebAuthn 提供支援的網路生物辨識技術使這一切成為可能。這是一個非常簡單的東西的奇特名稱:使用與手機指紋感應器或臉部識別相同的安全性來驗證我們的身份,但直接在我們的網路瀏覽器中進行。不再擔心密碼洩漏或被盜——只需快速掃描,我們就可以了。
在本教程中,我們將親自動手將指紋和 Face ID 登入整合到我們的 Angular 應用程式中。我們將介紹基本知識,例如 WebAuthn API 的工作原理以及我們需要在後端執行哪些操作以確保一切安全和順利。這比您想像的要容易,到最後,我們將為未來的身份驗證做好所有設定。所以,讓我們深入研究,讓登入變得輕而易舉!
好吧,在我們進入程式碼之前,讓我們快速了解一下 WebAuthn 的意思。將 WebAuthn 視為橋樑,將我們的應用程式與我們喜歡的手機上的生物識別功能(如指紋和 Face ID)連接起來,就在我們的瀏覽器中。它使用公鑰加密技術來驗證用戶身份,這意味著不再儲存駭客可以輕鬆竊取的普通舊密碼。相反,我們談論的是安全生成的金鑰,它使我們的登入既安全又無縫。
為了讓事情順利進行,我們需要了解 WebAuthn 遊戲中的幾個關鍵角色:PublicKeyCredentialCreationOptions 和 PublicKeyCredentialRequestOptions。不要讓長名稱嚇到您——它們只是告訴瀏覽器我們要如何註冊和驗證用戶身份的奇特方式。
這是我們設定新使用者憑證時的首選物件。它包括:
當需要驗證我們的使用者時,這個物件就會成為人們關注的焦點。它包括:
有了這些對象,我們的 Angular 應用程式將能夠指導用戶註冊其生物識別數據並快速、安全地進行身份驗證。接下來,我們將進入程式碼,看看如何在我們的應用程式中實現這個魔法!
在本節中,我們將指導您使用 WebAuthn 設定具有生物辨識驗證的 Angular 應用程式。我們將專注於使用指紋和 Face ID,所以讓我們動手吧!
首先,讓我們建立一個新的 Angular 專案。開啟終端機並輸入以下命令:
ng new web-biometrics-demo cd web-biometrics-demo ng serve
這會設定一個基本的 Angular 應用程序,運行 ngserve 將在 http://localhost:4200/ 上啟動您的應用程式。您應該會看到預設的 Angular 歡迎頁面。現在,我們已準備好整合 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 } }
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.
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; } } }
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.
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.
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:
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.
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:
Credential Verification:
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.
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 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中文網其他相關文章!