20241214 没爱了,我放弃,我折腾不动了
鼓捣了7天的免密码登录,我鼓捣不动了
鼓捣了7天的免密码登录,我鼓捣不动了
案例背景,调试WebAuthn Passkey Login Demo
的时候多注册了一大堆账号,然后点击登录的时候出现了如下选项,
深入刨析问题根源,是navigator.credentials.create()
,创建了一大堆,但是系统当成新账户来处理,那么就出大问题了,就是重复注册了一大堆凭证在电脑里面,
最后不懈努力查询到了与create相反的其他接口
应用背景
API进行调试的时候,服务端会对接口数据进行校验,避免接口被滥用,我们就需要对请求数据进行签名
例如请求
{
"id":"1",
"type":"99",
"pageNum":"2"
}
最后经过这么一签名
{
"id":"1",
"type":"99",
"pageNum":"2",
"timestamp":"1733676142",
"sign":"E2F42D80274469B439CE00D002DABB24"
}
难不成我们每次请求数据的时候就要进行计算,签名吗?
那不得多累呀或者启动代码进行签名然后请求?,最后根据第三方给的小脚本,让我对这个自动化签名可以一窥一二
背景意义,博客经常变更避免绝对地址对博客的影响
为了简化登录,给自己偷懒,就有了如下的方案
案例代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>WebAuthn Passkey Login Demo (前端模拟指纹登录)</title>
</head>
<body>
<button id="registerButton">注册 Passkey(模拟指纹注册)</button>
<button id="loginButton">使用 Passkey 登录(模拟指纹登录)</button>
<script>
// 获取页面上的注册和登录按钮元素
const registerButton = document.getElementById('registerButton');
const loginButton = document.getElementById('loginButton');
// 模拟存储已注册用户信息(仅前端模拟,实际应存储在后端)
const registeredUsers = {};
// 注册 Passkey 流程(模拟指纹注册)
registerButton.addEventListener('click', async () => {
try {
const publicKeyCredentialCreationOptions = {
// 依赖方(示例网站)相关信息
rp: {
name: "Your Website",
id: "www.guagau0127.fun"
},
// 用户信息
user: {
id: new Uint8Array(16), // 简单示例,实际应唯一标识用户,如哈希后的用户ID
name: "demo_user",
displayName: "Demo User"
},
// 挑战值,这里简单模拟生成,实际应由后端安全生成传递过来
challenge: Uint8Array.from(window.crypto.getRandomValues(new Uint8Array(32))),
pubKeyCredParams: [
{
type: "public-key",
alg: -7 // ES256算法对应的编号
},
{
type: "public-key",
alg: -257 // RS256算法对应的编号,添加此项以满足要求
}
],
// 认证器选择配置,优先使用生物识别(如指纹)验证
authenticatorSelection: {
authenticatorAttachment: "platform",
requireResidentKey: false,
userVerification: "preferred"
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
console.log('注册成功,凭证信息: ', credential);
// 模拟将凭证信息与用户关联存储(仅前端模拟,实际应发送到后端存储)
const { id } = credential;
registeredUsers[id] = credential;
} catch (error) {
console.error('注册凭证失败: ', error);
}
});
// 使用 Passkey 登录流程(模拟指纹登录)
loginButton.addEventListener('click', async () => {
try {
const publicKeyCredentialRequestOptions = {
challenge: Uint8Array.from(window.crypto.getRandomValues(new Uint8Array(32))), // 新的挑战值,模拟生成,实际后端生成
allowCredentials: Object.values(registeredUsers).map(user => ({
type: "public-key",
id: user.id.buffer // 修改此处,获取正确的ArrayBuffer类型数据作为id的值
})),
userVerification: "preferred"
};
const assertion = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions
});
console.log('登录成功,断言信息: ', assertion);
// 这里省略了发送到后端验证的步骤,仅前端模拟登录成功提示
alert('登录成功(模拟,实际需后端验证)');
} catch (error) {
console.error('登录失败: ', error);
}
});
</script>
</body>
</html>