实战教程:构建 Web3 身份验证流—钱包登录一步到位

·

Web3 身份验证是开发者圈长期讨论的高频话题。本文将用 Next.jsethers.jsWalletConnect 手把手搭一条“无用户名、无密码”的区块链登录链路,实现跨设备无缝体验。

核心关键词:Web3 身份验证、钱包登录、区块链登录、Next.js、ethers.js、WalletConnect、去中心化身份、以太坊钱包、签名验证、Web3 身份解决方案


为什么选择 Web3 身份验证?

与中心化服务不同,Web3 身份验证基于 区块链钱包与公钥加密。用户只需签名一条服务器随机下发的消息,即可证明“我就是我的地址”。无须注册、不会泄露姓名或邮箱,自由选择是否绑定 ENS/IDX/Ceramic 等去中心化身份协议。更棒的是,你可以给自己准备多个地址,对应不同的应用场景与角色。


技术拆解:核心流程 3 步曲

  1. 前端请求随机数:/api/auth
  2. 钱包对随机数签名
  3. 后端验证签名:/api/verify

代码极简版

// 前端(浏览器)
const signature = await signer.signMessage(randomNonce);

// 后端(Node.js)
const decodedAddress = ethers.utils.verifyMessage(randomNonce, signature);
if (decodedAddress.toLowerCase() === senderAddress.toLowerCase()) {
  // 身份验证通过
}

动手开发:10 分钟跑通完整 Demo

1. 初始化项目

npx create-next-app sign-in-with-ethereum
cd sign-in-with-ethereum
npm install ethers web3modal @walletconnect/web3-provider @toruslabs/torus-embed

2. 生成登录随机数

新建 pages/api/auth.js

import { users } from '../../utils/users';

export default function auth(req, res) {
  const { address } = req.query;
  let user = users[address];

  if (!user) {
    user = { address, nonce: Math.floor(Math.random() * 10_000_000) };
  } else {
    user.nonce = Math.floor(Math.random() * 10_000_000);
  }
  users[address] = user;
  res.status(200).json(user);
}

3. 服务器验证签名

新建 pages/api/verify.js

import { ethers } from 'ethers';
import { users } from '../../utils/users';

export default function verify(req, res) {
  const { address, signature } = req.query;
  const user = users[address];

  const decodedAddress = ethers.utils.verifyMessage(
    user.nonce.toString(),
    signature
  );
  const authenticated =
    decodedAddress.toLowerCase() === address.toLowerCase();

  res.status(200).json({ authenticated });
}

4. 本地“用户库”

新建 utils/users.js

export const users = {}; // 自托管极简 KV,生产请换 Ceramic/ThreadDB/GunDB

前端 UI:跨平台钱包连接

pages/index.js 关键片段(已删广告与冗余代码):

import { ethers } from 'ethers';
import Web3Modal from 'web3modal';
import WalletConnectProvider from '@walletconnect/web3-provider';

const providerOptions = {
  torus: {
    package: (await import('@toruslabs/torus-embed')).default,
  },
  walletconnect: {
    package: WalletConnectProvider,
    options: { infuraId: 'YOUR_INFURA_ID' },
  },
};

const web3Modal = new Web3Modal({
  network: 'mainnet',
  cacheProvider: false,
  providerOptions,
});

// 1. 连接钱包
async function connect() {
  const instance = await web3Modal.connect();
  const provider = new ethers.providers.Web3Provider(instance);
  const [account] = await provider.listAccounts();
  return { provider, account };
}

// 2. 签名登录
async function signIn({ account, provider }) {
  const { nonce } = await (await fetch(`/api/auth?address=${account}`)).json();
  const signature = await provider.getSigner().signMessage(nonce.toString());
  const res = await fetch(
    `/api/verify?address=${account}&signature=${signature}`
  );
  const { authenticated } = await res.json();
  return authenticated;
}

状态切换示例组件

{!connection ? (
  <button onClick={onConnect}>连接钱包</button>
) : !loggedIn ? (
  <button onClick={onSignIn}>以太坊一键登录</button>
) : (
  <p>欢迎,{account}</p>
)}

场景深挖:真实应用如何进阶?

  1. 防私钥重放
    每次登录都生成一次性 nonce,并设置 5–10 分钟 TTL。
  2. 跨链支持
    重构 providerOptions 即可添加 Solana、Polygon、BNB Smart Chain 等多链钱包。
  3. 零网络轮询体验
    cacheProvider: true 与 JWT/SessionCookie 结合,可让已连接用户 30 天内无感续登。

👉 若想深挖 Ceramic 3.0 去中心化身份存储,立即查看更多实战案例。


FAQ:80% 开发者的真实疑惑

Q1:用户更换浏览器会丢失登录态吗?
A:不会。身份核心在区块链地址与私钥;只要助记词仍在,重新运行钱包即可登录。

Q2:能不能完全离线签名?
A:可以。客户端本地生成签名后,把 signaturenonce 一并发送到后端即可,过程无需调用链上交易。

Q3:如何避免钓鱼网站伪造签名?
A:在随机字符串中嵌入域名、有效期与用户 IP,并在客户端展示 可读的待签内容,引导用户二次确认。

Q4:移动端白带钱包如何适配?
A:WalletConnect 已适配 MetaMask Mobile、Trust Wallet、Coinbase Wallet,扫码即可登录。

Q5:生产环境还需要什么安全策略?
A:引入 TLS、CSRF Token、JWT 不过期续签机制,并结合 Web3 Fraud Detection API 实时校验异常行为地址。

Q6:Ceramic vs ENS 身份协议选哪个?
A:Ceramic 适合高频读写的用户画像数据;ENS 适合静态身份信息(昵称、头像)。两者可并存,组合收益更大。


运行体验

npm run build
npm start

浏览器会自动打开 localhost:3000,MetaMask/WalletConnect/Torus 任意钱包均可测试。

👉 探索一下本教程完整源码仓库,立即 Fork 并二次开发!


延伸阅读与灵感

把今日学到的 钱包签名登录 应用在社交、电商、会员卡片或 NFT Market,你的应用即可跨越 Web2 与 Web3 的边界,给予用户“我即是私钥,私钥即是我”的极致自由。