Next.js 钱包登录:签名认证不是只拿地址当用户

📅 2026/7/3 2:19:35 👁️ 阅读次数 📝 编程学习
Next.js 钱包登录:签名认证不是只拿地址当用户

Next.js 钱包登录:签名认证不是只拿地址当用户

一、钱包地址不是登录态

很多 DApp 第一版会在前端连接钱包后,直接把地址当成用户身份。这样做可以展示界面,但不能算真正登录。用户地址可以被前端伪造,后端如果不验证签名,就无法确认请求者真的控制该钱包。钱包登录的核心是签名认证,而不是读取地址字符串。

Next.js 全栈应用里,登录流程应包含 nonce、签名消息、后端验签和会话建立。前端负责让用户签名,后端负责验证签名、检查 nonce 是否过期并创建 session。这样才能把钱包身份变成后端可信登录态。

签名认证的本质是把钱包私钥转化为一种身份证明机制——它告诉服务端"发起这个请求的人控制了这个地址",而不只是"浏览器里显示了这个地址字符串"。这一层区别在混合架构中尤其关键。如果你的产品同时有链上动作和链下状态,签名是唯一能在后端确认链上身份的手段,没有其他可信通道。前端拿地址发请求,和你拿一个userId字符串发请求没有本质区别——服务端不验,一切都不算登录。

这种模式还有历史包袱。早期 DApp 多是前端重量级、后端轻量的"胖客户端",数据从链上直接读,不需要传统登录态。但在当前端开始管用户资产、链下数据和个性化配置时,单纯依赖浏览器注入的地址就不够了。架构变了,认证方式也要跟着变。

二、认证链路:nonce 防重放,签名证明控制权

flowchart TD A[用户连接钱包] --> B[请求 nonce] B --> C[钱包签名消息] C --> D[后端验签] D --> E[创建 Session] E --> F[访问受保护 API]

nonce 是为了防重放。如果用户每次都签同一段消息,攻击者拿到旧签名后可能重复登录。后端应为每次登录生成随机 nonce,并设置过期时间。签名成功后,nonce 立即作废。

签名消息要清楚。建议包含域名、钱包地址、nonce、过期时间和用途。用户在钱包里看到消息时,至少能判断自己在登录哪个站点,而不是签一段神秘文本。

三、后端验签:不要信任前端传来的地址

下面是一个简化的验签思路。真实项目可使用viemethers

import { verifyMessage } from "viem"; export async function verifyWalletLogin(address: string, message: string, signature: string) { const ok = await verifyMessage({ address: address as `0x${string}`, message, signature: signature as `0x${string}`, }); if (!ok) { throw new Error("invalid wallet signature"); } }

验证通过后,后端再创建 cookie session 或 JWT。不要把签名本身当成长期 token。签名只是证明这次登录时用户控制地址,真正的会话还需要过期、刷新和注销机制。

如果支持多链,要明确地址格式和链 ID。有些登录只需要 EVM 地址,有些业务还要确认用户切换到了指定链。认证和业务链操作不要混在一起。

四、安全细节:域名、过期和注销都要有

签名消息中应包含当前域名,避免签名被其他站点复用。nonce 要短期有效,例如 5 分钟。登录后用户应能注销,服务端也要清理 session。Web3 登录不代表可以忽略传统 Web 安全。

CSRF、XSS 和 cookie 安全仍然重要。钱包登录解决的是身份控制权,不解决页面脚本被注入的问题。Next.js API 路由和服务端组件里处理用户数据时,仍要做权限校验。

最后,登录失败提示要友好。用户拒绝签名、钱包网络错误、nonce 过期和签名不匹配,是不同问题。错误清楚,用户才不会以为钱包坏了。

如果产品同时支持邮箱登录和钱包登录,还要设计账号绑定流程。用户可能先用邮箱注册,后来绑定钱包;也可能换钱包或解绑旧钱包。绑定时同样要签名验证,解绑时要确认还有其他登录方式,避免用户把自己锁在账号外。身份系统不要只考虑第一次登录。

五、总结

Next.js 钱包登录不能只拿地址当用户。正确流程是 nonce、签名、后端验签、会话建立和权限校验。Web3 身份仍然需要 Web 工程基本功,签名认证只是起点。