📢 Gate广场专属 #WXTM创作大赛# 正式开启!
聚焦 CandyDrop 第59期 —— MinoTari (WXTM),总奖池 70,000 枚 WXTM 等你赢!
🎯 关于 MinoTari (WXTM)
Tari 是一个以数字资产为核心的区块链协议,由 Rust 构建,致力于为创作者提供设计全新数字体验的平台。
通过 Tari,数字稀缺资产(如收藏品、游戏资产等)将成为创作者拓展商业价值的新方式。
🎨 活动时间:
2025年8月7日 17:00 - 8月12日 24:00(UTC+8)
📌 参与方式:
在 Gate广场发布与 WXTM 或相关活动(充值 / 交易 / CandyDrop)相关的原创内容
内容不少于 100 字,形式不限(观点分析、教程分享、图文创意等)
添加标签: #WXTM创作大赛# 和 #WXTM#
附本人活动截图(如充值记录、交易页面或 CandyDrop 报名图)
🏆 奖励设置(共计 70,000 枚 WXTM):
一等奖(1名):20,000 枚 WXTM
二等奖(3名):10,000 枚 WXTM
三等奖(10名):2,000 枚 WXTM
📋 评选标准:
内容质量(主题相关、逻辑清晰、有深度)
用户互动热度(点赞、评论)
附带参与截图者优先
📄 活动说明:
内容必须原创,禁止抄袭和小号刷量行为
获奖用户需完成 Gate广场实名
SIWE:以太坊登录新标准实践指南
SIWE:以太坊登录的强大工具
SIWE (Sign-In with Ethereum) 是一种在以太坊上验证用户身份的方法。类似于发起交易,它通过签名来证明用户对钱包的控制权。目前,大多数主流钱包插件都已支持这种简单的身份验证方式。
本文主要讨论以太坊上的签名场景,不涉及其他公链如 Solana、SUI 等。
什么时候需要 SIWE?
如果你的 Dapp 具有以下需求,可以考虑使用 SIWE:
对于主要提供查询功能的 Dapp(如区块浏览器),可能并不需要 SIWE。
虽然通过钱包连接可以在前端证明身份,但对于需要后端支持的 API 调用,仅传递地址是不够的,因为地址是公开信息,任何人都可以使用。
SIWE 的原理和流程
SIWE 的流程可以概括为三个步骤:连接钱包 - 签名 - 获取身份标识。
连接钱包
这是 Web3 应用中常见的操作,通过钱包插件连接用户的钱包。
签名
签名步骤包括获取 Nonce 值、钱包签名和后端签名校验。
首先从后端获取随机生成的 Nonce 值,后端会将其与当前地址关联。
前端获取 Nonce 值后,构建签名内容,包括 Nonce、域名、链 ID 等信息,然后使用钱包的签名方法进行签名。
最后将签名发送给后端进行验证。
获取身份标识
后端验证签名通过后,会返回用户身份标识(如 JWT)。前端后续请求时带上地址和身份标识,即可证明对钱包的所有权。
实践 SIWE
下面我们通过一个简单的 Demo 来实践 SIWE 的基本流程,目标是让 Dapp 能返回用于身份校验的 JWT。
注意:此 Demo 仅用于展示基本流程,生产环境使用可能存在安全隐患。
准备工作
我们使用 Next.js 开发全栈应用,需要准备 Node.js 环境。
安装依赖
首先安装 Next.js:
npx create-next-app@14
按提示完成安装。
进入项目目录并启动:
npm run dev
访问 localhost:3000 可以看到基本的 Next.js 项目。
安装 SIWE 相关依赖
我们使用 Ant Design Web3 来连接钱包并实现 SIWE 功能:
npm install antd @ant-design/web3 @ant-design/web3-wagmi wagmi viem @tanstack/react-query --save
引入 Wagmi
在 layout.tsx 中引入 WagmiProvider:
jsx "use client"; import { getNonce, verifyMessage } from "@/app/api"; import { Mainnet, MetaMask, OkxWallet, TokenPocket, WagmiWeb3ConfigProvider, WalletConnect, } from "@ant-design/web3-wagmi"; import { QueryClient } from "@tanstack/react-query"; import React from "react"; import { createSiweMessage } from "viem/siwe"; import { http } from "wagmi"; import { JwtProvider } from "./JwtProvider";
const YOUR_WALLET_CONNECT_PROJECT_ID = "c07c0051c2055890eade3556618e38a6"; const queryClient = new QueryClient();
const WagmiProvider: React.FC = ({ children }) => { const [jwt, setJwt] = React.useState(null);
return ( <wagmiweb3configprovider siwe="{{" getnonce:="" async="" (address)=""> (await getNonce(address)).data, createMessage: (props) => { return createSiweMessage({ ...props, statement: "Ant Design Web3" }); }, verifyMessage: async (message, signature) => { const jwt = (await verifyMessage(message, signature)).data; setJwt(jwt); return !!jwt; }, }} chains={[Mainnet]} transports={{ [Mainnet.id]: http(), }} walletConnect={{ projectId: YOUR_WALLET_CONNECT_PROJECT_ID, }} wallets={[ MetaMask(), WalletConnect(), TokenPocket({ group: "Popular", }), OkxWallet(), ]} queryClient={queryClient} > {children} ); };
export default WagmiProvider;
然后添加连接钱包的按钮:
jsx "use client"; import type { Account } from "@ant-design/web3"; import { ConnectButton, Connector } from "@ant-design/web3"; import { Flex, Space } from "antd"; import React from "react"; import { JwtProvider } from "./JwtProvider";
export default function App() { const jwt = React.useContext(JwtProvider);
const renderSignBtnText = ( defaultDom: React.ReactNode, account?: Account ) => { const { address } = account ?? {}; const ellipsisAddress = address ? ${address.slice(0, 6)}...${address.slice(-6)} : ""; return Sign in as ${ellipsisAddress}; };
return ( <>
这样就实现了一个基本的 SIWE 登录框架。
接口实现
现在来实现后端需要的一些接口。
Nonce
生成随机 Nonce 并与地址关联:
javascript import { randomBytes } from "crypto"; import { addressMap } from "../cache";
export async function GET(request: Request) { const { searchParams } = new URL(request.url); const address = searchParams.get("address");
if (!address) { throw new Error("Invalid address"); } const nonce = randomBytes(16).toString("hex"); addressMap.set(address, nonce); return Response.json({ data: nonce, }); }
verifyMessage
验证签名并返回 JWT:
javascript import { createPublicClient, http } from "viem"; import { mainnet } from "viem/chains"; import jwt from "jsonwebtoken"; import { parseSiweMessage } from "viem/siwe"; import { addressMap } from "../cache";
const JWT_SECRET = "your-secret-key"; // 请使用更安全的密钥,并添加对应的过期校验等
const publicClient = createPublicClient({ chain: mainnet, transport: http(), });
export async function POST(request: Request) { const { signature, message } = await request.json();
const { nonce, address = "0x" } = parseSiweMessage(message);
if (!nonce || nonce !== addressMap.get(address)) { throw new Error("Invalid nonce"); }
const valid = await publicClient.verifySiweMessage({ message, address, signature, });
if (!valid) { throw new Error("Invalid signature"); }
const token = jwt.sign({ address }, JWT_SECRET, { expiresIn: "1h" }); return Response.json({ data: token, }); }
至此,一个基本的 SIWE 登录 Dapp 就开发完成了。
性能优化
为提高验证速度,建议使用专门的节点服务。这里我们使用 ZAN 的节点服务,替换 publicClient 的默认 RPC:
javascript const publicClient = createPublicClient({ chain: mainnet, transport: http('), //替换为获取到的 ZAN 节点服务 RPC });
这样可以显著减少验证时间,提高接口速度。