Web3 身份验证是开发者圈长期讨论的高频话题。本文将用 Next.js、ethers.js 和 WalletConnect 手把手搭一条“无用户名、无密码”的区块链登录链路,实现跨设备无缝体验。
核心关键词:Web3 身份验证、钱包登录、区块链登录、Next.js、ethers.js、WalletConnect、去中心化身份、以太坊钱包、签名验证、Web3 身份解决方案
为什么选择 Web3 身份验证?
与中心化服务不同,Web3 身份验证基于 区块链钱包与公钥加密。用户只需签名一条服务器随机下发的消息,即可证明“我就是我的地址”。无须注册、不会泄露姓名或邮箱,自由选择是否绑定 ENS/IDX/Ceramic 等去中心化身份协议。更棒的是,你可以给自己准备多个地址,对应不同的应用场景与角色。
技术拆解:核心流程 3 步曲
- 前端请求随机数:/api/auth
- 钱包对随机数签名
- 后端验证签名:/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-embed2. 生成登录随机数
新建 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>
)}场景深挖:真实应用如何进阶?
- 防私钥重放
每次登录都生成一次性nonce,并设置 5–10 分钟 TTL。 - 跨链支持
重构providerOptions即可添加 Solana、Polygon、BNB Smart Chain 等多链钱包。 - 零网络轮询体验
用cacheProvider: true与 JWT/SessionCookie 结合,可让已连接用户 30 天内无感续登。
👉 若想深挖 Ceramic 3.0 去中心化身份存储,立即查看更多实战案例。
FAQ:80% 开发者的真实疑惑
Q1:用户更换浏览器会丢失登录态吗?
A:不会。身份核心在区块链地址与私钥;只要助记词仍在,重新运行钱包即可登录。
Q2:能不能完全离线签名?
A:可以。客户端本地生成签名后,把 signature 与 nonce 一并发送到后端即可,过程无需调用链上交易。
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 并二次开发!
延伸阅读与灵感
- SpruceID SIWE SSR —— 服务端渲染版本模板
- ENS.JS —— 解析 ENS 域名并获取用户社交头像
- Ceramic & IDX Workshop —— 深度动手实验,构建去中心化用户数据库
把今日学到的 钱包签名登录 应用在社交、电商、会员卡片或 NFT Market,你的应用即可跨越 Web2 与 Web3 的边界,给予用户“我即是私钥,私钥即是我”的极致自由。