📢 Gate广场 #NERO发帖挑战# 秀观点赢大奖活动火热开启!
Gate NERO生态周来袭!发帖秀出NERO项目洞察和活动实用攻略,瓜分30,000NERO!
💰️ 15位优质发帖用户 * 2,000枚NERO每人
如何参与:
1️⃣ 调研NERO项目
对NERO的基本面、社区治理、发展目标、代币经济模型等方面进行研究,分享你对项目的深度研究。
2️⃣ 参与并分享真实体验
参与NERO生态周相关活动,并晒出你的参与截图、收益图或实用教程。可以是收益展示、简明易懂的新手攻略、小窍门,也可以是行情点位分析,内容详实优先。
3️⃣ 鼓励带新互动
如果你的帖子吸引到他人参与活动,或者有好友评论“已参与/已交易”,将大幅提升你的获奖概率!
NERO热门活动(帖文需附以下活动链接):
NERO Chain (NERO) 生态周:Gate 已上线 NERO 现货交易,为回馈平台用户,HODLer Airdrop、Launchpool、CandyDrop、余币宝已上线 NERO,邀您体验。参与攻略见公告:https://www.gate.com/announcements/article/46284
高质量帖子Tips:
教程越详细、图片越直观、互动量越高,获奖几率越大!
市场见解独到、真实参与经历、有带新互动者,评选将优先考虑。
帖子需原创,字数不少于250字,且需获得至少3条有效互动
SIWE身份验证:让Dapp用户认证更安全可靠
SIWE简介:让你的Dapp身份验证更安全
SIWE(Sign-In with Ethereum)是一种基于以太坊的用户身份验证方式。类似于发起交易,用户通过签名来证明对钱包的控制权。目前大多数主流钱包插件都已支持这种简单的身份验证方式。
SIWE适用场景
如果你的Dapp具有以下需求,可以考虑使用SIWE:
对于以查询为主的Dapp(如区块浏览器),则不一定需要SIWE。
值得注意的是,仅仅通过钱包连接并不能完全证明身份。对于需要后端支持的接口调用,仍需要额外的身份验证,否则任何人都可能"借用"公开的地址信息。
SIWE工作原理
SIWE的基本流程包括三个步骤:连接钱包、签名、获取身份标识。
连接钱包:通过钱包插件连接用户钱包
签名:
获取身份标识: 后端验证签名通过后,返回用户身份标识(如JWT)
SIWE实践
下面我们通过一个简单的Demo来实践SIWE流程。注意,此Demo仅用于演示基本流程,不宜直接用于生产环境。
环境准备
我们使用Next.js来开发全栈应用,需要准备Node.js环境。
安装依赖
首先创建Next.js项目:
npx create-next-app@14
进入项目目录后,安装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";
const YOUR_WALLET_CONNECT_PROJECT_ID = "xxx"; const queryClient = new QueryClient();
const WagmiProvider = ({ 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 { ConnectButton } from "@ant-design/web3"; import React from "react"; import { JwtProvider } from "./JwtProvider";
export default function App() { const jwt = React.useContext(JwtProvider);
const renderSignBtnText = (defaultDom, account) => { const { address } = account ?? {}; const ellipsisAddress = address ? ${address.slice(0, 6)}...${address.slice(-6)} : ""; return Sign in as ${ellipsisAddress}; };
return ( <> <connectbutton.signin label="{renderSignBtnText}" onsignmessagesuccess="{()" ==""> { console.log("Sign message success"); }} />
实现后端接口
Nonce接口
javascript import { randomBytes } from "crypto"; import { addressMap } from "../cache";
export async function GET(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, }); }
验证签名接口
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) { 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, }); }
优化建议
为提高验证速度,建议使用专门的节点服务。可以使用ZAN节点服务,替换默认RPC:
javascript const publicClient = createPublicClient({ chain: mainnet, transport: http('), });
这样可以显著减少验证时间,提升接口响应速度。