webauthn是一种基于公私钥加密的web标准,通过浏览器与设备内置的生物识别系统(如指纹、面部识别)安全交互,实现无密码登录。其工作原理分为两个阶段:首先是凭证注册,服务器生成挑战并由认证器生成密钥对,私钥存于设备,公钥由服务器存储;其次是凭证认证,用户通过生物识别触发私钥签名,服务器用公钥验证签名以确认身份。该机制依赖web authentication api,确保挑战唯一、来源合法,并通过签名计数器防克隆,需配合回退登录方式和服务器端安全验证库(如@simplewebauthn/server)实现完整流程,是目前集成生物认证最安全且标准化的解决方案。

将生物认证(如指纹或面部识别)集成到表单中,核心在于利用现代浏览器提供的 Web Authentication API (WebAuthn)。它不是让你直接访问用户的生物传感器,而是通过浏览器作为中介,与设备的原生认证机制(如Windows Hello、macOS的Touch ID、iOS的Face ID/Touch ID)进行安全交互,完成用户身份的验证。
实现表单中的生物认证,主要依赖于WebAuthn API来完成凭证的注册(用户将生物特征与你的网站关联)和后续的认证(用户通过生物特征登录)。你的Web应用(Relying Party)与用户的设备(Authenticator)之间通过浏览器进行通信,服务器端则负责生成挑战(Challenge)、存储用户的公钥,并验证认证器的签名。这个过程是高度安全的,因为它利用了设备内置的硬件安全模块,并且能有效抵抗钓鱼攻击。
WebAuthn,全称Web Authentication API,是W3C制定的一项标准,也是FIDO2认证协议的核心组成部分。简单来说,它让网页应用能够以一种安全、标准化的方式与用户的认证器(可以是内置的生物识别传感器,也可以是外部的FIDO安全密钥)进行交互,实现无密码或多因素认证。
它工作的流程,在我看来,可以拆分成两个主要阶段:
1. 凭证注册(Credential Registration): 这就像用户第一次在你的网站上“录入”他的生物特征。当用户选择使用生物识别登录时:
navigator.credentials.create()
2. 凭证认证(Credential Authentication): 当用户下次登录时,他不再需要输入密码,而是通过生物识别来证明“我是我”。
navigator.credentials.get()
整个过程听起来有点绕,但核心就是用一套公私钥体系,把用户设备的生物识别能力安全地嫁接到Web登录流程中。
说实话,WebAuthn虽然强大,但实际集成起来,还是有些地方需要特别留意的,别以为它很简单。
@simplewebauthn/server
webauthn
webauthn4j
要让前端和后端“说上话”,并正确地处理WebAuthn流程,你需要一些关键的代码片段和逻辑。这里我不会给出完整的可运行代码,因为那太长了,而且具体实现会依赖于你选择的WebAuthn库和后端语言,但我们可以看看核心的思路。
前端(JavaScript)部分:
当用户点击“使用指纹/面部注册”按钮时:
// 假设后端接口返回了创建凭证所需的选项
async function registerBiometricCredential() {
try {
const response = await fetch('/api/webauthn/register/options'); // 从后端获取注册选项
const options = await response.json();
// 将Base64 URL编码的挑战和用户ID等转换为ArrayBuffer
options.challenge = base64UrlToUint8Array(options.challenge);
options.user.id = base64UrlToUint8Array(options.user.id);
if (options.excludeCredentials) {
options.excludeCredentials.forEach(cred => {
cred.id = base64UrlToUint8Array(cred.id);
});
}
// 调用WebAuthn API创建凭证
const credential = await navigator.credentials.create({
publicKey: options
});
// 将凭证对象序列化并发送给后端进行验证和存储
const attestationResponse = {
id: credential.id,
rawId: uint8ArrayToBase64Url(credential.rawId),
response: {
clientDataJSON: uint8ArrayToBase64Url(credential.response.clientDataJSON),
attestationObject: uint8ArrayToBase64Url(credential.response.attestationObject),
},
type: credential.type,
clientExtensionResults: credential.clientExtensionResults,
};
const verifyResponse = await fetch('/api/webauthn/register/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(attestationResponse),
});
if (verifyResponse.ok) {
alert('生物认证注册成功!');
} else {
const errorData = await verifyResponse.json();
alert('注册失败: ' + (errorData.message || '未知错误'));
}
} catch (error) {
console.error('注册生物认证失败:', error);
alert('操作取消或出现错误。');
}
}
// 辅助函数:Base64 URL字符串转Uint8Array
function base64UrlToUint8Array(base64Url) { /* ... 实现细节 ... */ }
// 辅助函数:Uint8Array转Base64 URL字符串
function uint8ArrayToBase64Url(uint8Array) { /* ... 实现细节 ... */ }当用户点击“使用指纹/面部登录”按钮时:
// 假设后端接口返回了认证所需的选项
async function authenticateBiometricCredential() {
try {
const response = await fetch('/api/webauthn/authenticate/options'); // 从后端获取认证选项
const options = await response.json();
options.challenge = base64UrlToUint8Array(options.challenge);
if (options.allowCredentials) {
options.allowCredentials.forEach(cred => {
cred.id = base64UrlToUint8Array(cred.id);
});
}
// 调用WebAuthn API获取凭证
const credential = await navigator.credentials.get({
publicKey: options
});
// 将凭证对象序列化并发送给后端进行验证
const assertionResponse = {
id: credential.id,
rawId: uint8ArrayToBase64Url(credential.rawId),
response: {
clientDataJSON: uint8ArrayToBase64Url(credential.response.clientDataJSON),
authenticatorData: uint8ArrayToBase64Url(credential.response.authenticatorData),
signature: uint8ArrayToBase64Url(credential.response.signature),
userHandle: credential.response.userHandle ? uint8ArrayToBase64Url(credential.response.userHandle) : null,
},
type: credential.type,
clientExtensionResults: credential.clientExtensionResults,
};
const verifyResponse = await fetch('/api/webauthn/authenticate/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(assertionResponse),
});
if (verifyResponse.ok) {
alert('生物认证登录成功!');
// 重定向或更新UI
} else {
const errorData = await verifyResponse.json();
alert('登录失败: ' + (errorData.message || '未知错误'));
}
} catch (error) {
console.error('认证生物认证失败:', error);
alert('操作取消或出现错误。');
}
}后端验证逻辑概览(以Node.js + @simplewebauthn/server
注册验证:
attestationResponse
options
verifyRegistrationResponse
clientDataJSON
attestationObject
verified
credentialID
publicKey
counter
publicKey
认证验证:
assertionResponse
options
credentialID
publicKey
verifyAuthenticationResponse
clientDataJSON
authenticatorData
publicKey
signature
signature counter
counter
这套体系虽然初看起来有些复杂,但一旦理解了其背后的安全原理和WebAuthn API的设计,你会发现它确实是目前实现生物认证集成最可靠、最标准的方式。
以上就是表单中的生物认证怎么集成?如何支持指纹或面部识别?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号