📢 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 });
這樣可以顯著減少驗證時間,提高接口速度。