正直に言うと、モバイル アプリと同じように、指紋や Face ID を使用して Web サイトにログインできればと誰もが思ったことがあるでしょう?ウェブ生体認証のおかげで、その夢はそれほど遠い夢ではなくなりました。長くて複雑なパスワードを捨てて、指紋や顔を使ってお気に入りの Web サイトにサインインすることを想像してみてください。素敵ですね?
WebAuthn を活用した Web 生体認証により、これが可能になります。これは非常に単純なものに対する派手な名前です。携帯電話の指紋センサーや顔認識と同じ種類のセキュリティを使用して、Web ブラウザーで直接認証することです。パスワードが漏洩したり盗まれたりする心配はもうありません。簡単にスキャンするだけで大丈夫です。
このチュートリアルでは、指紋と 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 を統合する準備が整いました。
生体認証を使用した登録や認証など、すべての WebAuthn 機能を管理するには、Angular のサービスが必要です。次を実行してこのサービスを作成しましょう:
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:
凭证验证:
不匹配或无效响应:如果质询响应与预期值不匹配,或者 WebAuthn 凭据未正确验证,后端会返回错误,以防止未经授权的访问。
回退到密码:如果 WebAuthn 失败或不可用,系统可以恢复到传统的密码验证,确保用户仍然可以访问其帐户。
数据完整性:WebAuthn 凭据的完整性至关重要。存储或传输中的任何修改都会导致验证失败,从而确保身份验证过程的安全。
挑战随机数:使用独特的、有时间限制的挑战可确保响应无法重复使用,从而防止重放攻击。
公钥存储:仅存储公钥(不能用于模拟用户)可以增强安全性,因为私钥保留在客户端设备上。
通过遵循这些原则,后端可以有效地管理生物识别身份验证,确保为想要在 Angular 应用中使用指纹或 Face ID 等功能的用户提供安全、无缝的体验。
在本教程中,我们介绍了使用 WebAuthn 将生物识别身份验证与 Angular 集成。我们涵盖了基础知识,从理解关键的 WebAuthn 对象(如 PublicKeyCredentialCreationOptions 和 PublicKeyCredentialRequestOptions)到设置 Angular 服务和 UI 组件以实现顺利的注册和登录过程。我们还讨论了安全处理生物识别身份验证所需的后端注意事项。
对于那些渴望看到 WebAuthn 实际应用的人,我提供了一个演示和一个具有完整实现的存储库。您可以在此处查看演示,并在 GitHub 上的此存储库中探索源代码。
采用生物识别身份验证不仅可以增强安全性,还可以简化用户体验,为未来像指纹扫描或快速面部识别一样轻松的登录铺平道路。当您将这些功能集成到 Angular 应用程序中时,您将为构建更安全、更用户友好的网络做出贡献。快乐编码!
以上がWebAuthn を使用して Angular アプリに指紋認証と Face ID 認証を統合する: ステップバイステップ ガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。