分类 默认分类 下的文章

应用背景
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>