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、过期时间和用途。用户在钱包里看到消息时至少能判断自己在登录哪个站点而不是签一段神秘文本。三、后端验签不要信任前端传来的地址下面是一个简化的验签思路。真实项目可使用viem或ethers。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 工程基本功签名认证只是起点。