SIWE(Sign-In with Ethereum)登录流程概述
<!--StartFragment-->
SIWE(Sign-In with Ethereum)登录流程概述
什么是SIWE?
SIWE(Sign-In with Ethereum)是一个以太坊登录的开放标准(EIP-4361),它允许用户通过钱包签名一条结构化的消息来安全地验证身份,而无需进行链上交易或支付Gas费。
核心思想
SIWE的核心是"用户用私钥对一条结构化的登录消息签名,服务端通过验证签名来确认身份"。整个过程完全链下,无需链上交易。
整体流程(简化版)
graph TD
A[用户访问网站] --> B[前端请求登录]
B --> C[后端生成随机Nonce]
C --> D[返回登录消息模板]
D --> E[钱包弹出签名请求]
E --> F[用户查看并签名]
F --> G[发送签名到后端验证]
G --> H[验证成功创建会话]
H --> I[返回会话令牌]
详细步骤
第1步:前端请求登录挑战
前端向后端请求一个登录挑战,后端返回一个结构化的登录消息模板,包含:
- 域名
- 用户地址
- 随机Nonce
- 过期时间
- 声明语句
示例登录消息:
example.com wants you to sign in with your Ethereum account:
0x1234...5678
Please sign to login to Example App.
URI: https://example.com
Version: 1
Chain ID: 1
Nonce: abc123def456
Issued At: 2023-10-01T10:00:00Z
Expiration Time: 2023-10-01T10:05:00Z
第2步:用户签名
前端将这条结构化的消息发送给用户的钱包(如MetaMask),钱包弹出签名请求,用户可以看到完整的消息内容并确认签名。
关键特点:
- 用户可以看到完整的消息内容,知道自己在为什么签名
- 这是链下签名,无需Gas费
- 签名是一次性的,针对特定Nonce
第3步:后端验证签名
前端将签名结果、原始消息和用户地址一起发送给后端,后端进行验证:
- 检查消息完整性:验证消息中的域名、过期时间等是否正确
- 验证签名有效性:通过密码学验证签名确实是由该地址对应的私钥生成的
- 检查Nonce:确保这个Nonce是有效的、未使用过的
- 检查时间:确保消息没有过期
第4步:建立会话
验证成功后,后端:
- 标记这个Nonce为已使用(防止重放攻击)
- 创建一个会话(如JWT令牌)
- 将会话令牌返回给前端
第5步:后续请求
前端在后续请求中携带会话令牌,后端验证令牌有效性并返回相应的用户数据。
SIWE消息的完整结构
一个标准的SIWE消息包含以下字段:
{域名} wants you to sign in with your Ethereum account:
{用户地址}
{声明语句}
URI: {请求URI}
Version: 1
Chain ID: {链ID}
Nonce: {随机Nonce}
Issued At: {签发时间}
Expiration Time: {过期时间}
Not Before: {生效时间} # 可选
Request ID: {请求ID} # 可选
Resources: # 可选
- {资源1}
- {资源2}
为什么SIWE更安全?
- 结构化消息:用户清楚地知道自己在为什么签名
- 防重放攻击:每个Nonce只能使用一次
- 上下文明确:包含域名、时间等信息,防止跨站攻击
- 标准化:EIP-4361是开放标准,各钱包统一支持
- 无Gas成本:纯链下操作,无需支付费用
与传统签名方案的对比
| 方面 | 传统方案 | SIWE方案 |
|---|---|---|
| 用户可见性 | 随机字符串,用户不知道签的是什么 | 结构化的英文消息,用户完全清楚内容 |
| 标准化 | 无标准,每个应用自己定义 | 统一的EIP-4361标准 |
| 安全性 | 依赖应用实现,可能有安全漏洞 | 标准化验证,安全性更高 |
| 钱包支持 | 钱包只显示签名字符串 | 钱包可以专门优化SIWE显示 |
| 用户体验 | 较差,用户不明确签名的内容 | 较好,用户知道这是登录操作 |
实际应用示例
// 前端代码示例
async function signInWithEthereum() {
// 1. 连接钱包获取地址
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
const address = accounts[0];
// 2. 从后端获取登录消息
const response = await fetch('/api/auth/nonce');
const { message } = await response.json();
// 3. 用户签名
const signature = await window.ethereum.request({
method: 'personal_sign',
params: [message, address],
});
// 4. 发送验证
const verifyResponse = await fetch('/api/auth/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message, signature, address }),
});
// 5. 获取会话令牌
const { token } = await verifyResponse.json();
return token;
}
总结
SIWE的核心流程是:
- 后端生成:包含随机Nonce的结构化登录消息
- 用户签名:用户查看完整消息内容并确认签名
- 后端验证:验证签名、Nonce、过期时间等
- 建立会话:创建传统Web会话令牌
关键优势:
- 用户友好:知道自己在为什么签名
- 标准化:统一的消息格式
- 无Gas:链下签名,无需费用
- 安全:防重放、防跨站
- 钱包支持好:主流钱包都支持
SIWE是目前以太坊登录的事实标准,被OpenSea、Uniswap等主流dApp采用,提供了最佳的安全性和用户体验平衡。
<!--EndFragment-->
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
区块链技术网

发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。