MetaMask以太坊一键登录设计 | DAPP登录设计

概述

您可以前往我的博客获得更好的阅读体验。

在目前的网站用户体系搭建中,社会化登录主要依赖于Google、QQ等服务商,中心化趋势较强。在Web3中,作为网站建设者的我们应该考虑使用去中心化的登录方式。在此篇博客中,我们将以使用MetaMask钱包中的API为例介绍去中心化登录的基本方式。

我会介绍前端页面的搭建和后端服务的设计。我选择了Vue作为前端页面的框架,同时使用了MetaMask插件提供的API接口。在后端为降低成本,我采用了CloudFlare Worker作为后端,主要使用WorkerKV服务。

本文的主要思路来自这篇文章,但根据最新的MetaMsk的API和cloudflare worker的新特性,我对此文章的内容进行了一些改进,但总体思路是相同的。

登录流程

由于以太坊等加密货币自身建立在非对称加密基础上,我们应该考虑使用使用非对称加密的功能来实现登录。登录的本质是用户对个人身份的证明,在过去的登录方式中,我们采用密码、手机或邮箱验证码实现。而在Web3中,以太坊等区块链天然的提供了一种工具实现这一过程,即签名。
签名是指用户使用私钥对数据进行签名,签名后的数据可以用公钥来验证。我们可以使用MetaMask中的签名API实现此流程,您可以查阅此页面来查看所有属于MetaMask的签名API,但在此教程中我们会选择最新的signTypedData_v4API,因为此签名方法更加安全且对用户友好。

用户对什么数据进行签名?这应该由开发者决定,签名内容应该在后端生成后发给前端,之后前端用户对其进行签名,再将签名后的数据与个人以太坊账户地址一同回传给后端,后端对数据进行验签,判断数据是否与以太坊账户地址相同。如果相同,则返回登录凭证,在此教程中,我们将返回JWT。如果不同,则返回登录失败消息。总体流程如下图所示:

登录流程

登录按钮实现(前端)

我们首先实现登录的第一步,实现请求后端获取签名内容和获取用户的以太坊账户地址。至于后端如何实现签名内容生成我们将在后文介绍。

首先给出Vue的基本框架:

<template>
  <div>
    <button @click="login" v-if="metaMaskSupport">
        Login
    </button>
  </div>
</template>

<script>
  import axios from "axios";
  export default {
      data() {
          return {
              metaMaskSupport: false,
              ethAccount: null,
              sign: null,
              nonces: null,
          }
      },
      mounted() {
          this.metaMaskSupport = window.ethereum && window.ethereum.isMetaMask;
      },
      methods: {
          login() {
              //具体实现方式将在下文给出
          }
      }
  }
</script>

为了方便后续代码编写,我们导入了知名网络请求库axios,您需要使用以下命令安装:

npm install axios

我们在data()中定义了一些数据,其中包括:

  • metaMaskSupport:是否支持MetaMask,如果不支持,则不显示登录按钮

  • ethAccount:用户的以太坊账户地址

  • sign:签名结果

  • nonces:用于防止重放攻击的nonce(将在后文介绍)

mounted()中,我们完成了基本的初始化,使用window.ethereum && window.ethereum.isMetaMask赋值给metaMaskSupport,这段代码用于判断用户是否安装了MetaMask插件。

接下来,我们会在完善login()方法的第一部分,获取用户的以太坊账户地址。

window.ethereum.request({
    method: 'eth_requestAccounts' }).then(
    accounts => {
   
        this.ethAccount = accounts[0]
        console.log(this.ethAccount);
    }
)

该段代码主要基于MetaMask文档中的此部分。在此处,我们使用了JavaScript中的异步请求,并且使用MetaMask APIwindow.ethereum.request方法获取用户的以太坊账户地址并将其赋值给this.ethAccount,最终在console中输出用户的以太坊账户地址。

以上基本完成了登录的第一步,接下来我们会介绍后端实现签名内容生成的部分。

签名内容生成(后端)

基础环境搭建

为了代码内容的简单化,我们在此处假设您已经安装了Cloudflare Wrangler并已经搭建了基本的CloudFlare Worker的开发环境。如果您对此不熟悉,您可以查阅此文档

下列代码的前提是您已经完成了wrangler的登录,具体内容可以参考此文档

首先使用此命令创建开发环境:

wrangler init web3login

在完成项目初始化后,您获得的目录结构应该如下图所示:

项目目录

以下内容主要关于kv的绑定问题,如果您认为我的表述较为奇怪,您可以自行查阅cloudflare的kv文档

然后您需要绑定您的kvwrangler代码中使用kv数据库,可以使用下述命令:

wrangler kv:namespace create web3login

kv bind

根据提示,将此代码运行后的结果添加到wrangler.toml中,如下:

name = "bloguse"
main = "src/index.js"
compatibility_date = "2022-06-08"

kv_namespaces = [{ binding = "web3login", id = "自行替换" }]

由于Worker的自身的限制,为了在dev中使用kv,我们需要在终端键入以下命令:

wrangler kv:namespace create web3login --preview

kv preview

根据提示,将此代码运行后的结果添加到wrangler.toml中,如下:

name = "bloguse"
main = "src/index.js"
compatibility_date = "2022-06-08"

kv_namespaces = [{ binding = "web3login", id = "自行替换", preview_id = "自行替换" }]

我们也需要安装一些必要的npm包,主要需要eth-sig-util,您可以通过此链接查阅它的开源仓库,你也可以通过这个链接查阅它的文档。

使用以下命令,您可以安装此库:

npm install @metamask/eth-sig-util

yarn add @metamask/eth-sig-util

nonces生成及存储

在前述内容中,我们已经得到了用户的ethAccount和基础开发环境的搭建,接下来我们考虑如何生成签名所需要的nonces。为了验证用户签名是否正确,我们需要存储用户的签名nonces和以太坊地址,这是一个简单的key-value数据,我们可以直接使用CloudFlare开发的kv数据库。

此处我们假设前端返回的数据结构如下:

{
    
  "from": this.ethAccount 
}

即仅向后端返回ethAccount字段。

以此数据结构为基础,我们给出后端的实现。

addEventListener("fetch", event => {
   
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
   
  if (request.method === "PUT") {
   
    let data = await request.json();
    let key = data.from;
    let nonces = Math.floor(Math.random() * 1000000)
    await loginKV.put(key, nonces, {
    expirationTtl: 120 })
    console.log(`${
     key} has been logged in`)
    return new Response(JSON.stringify({
    "nonces": nonces, "key": key }), {
   
      headers: {
   
        'content-type': 'application/json;charset=UTF-8',
        'Access-Control-Allow-Origin': '*'
      },
    });
  } else if (request.method === "OPTIONS") {
   
    const responseHeaders = new Headers();
    responseHeaders.set('Access-Control-Allow-Origin', '*');
    responseHeaders.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    responseHeaders.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    responseHeaders.set('Access-Control-Max-Age', '86400');
    return new Response("", {
   
      headers: responseHeaders
    })
  }
}

addEventListener功能为接受前端的请求,并将其转交给handleRequest函数进行处理

handleRequest函数的主要功能是:

  1. 接受PUT请求返回nonces并将其存储在KV中,nonces使用随机数生成,如果您需要严格的密码学保证,您可以选择密码学随机数生成的crypto.getRandomValues函数,具体调用发送可以参考CloudflareWorker文档。然后使用Worker直接调用kv的函数将此值直接推进数据库中,具体函数可参考文档,值得注意的是此处expirationTtl(过期删除时间)设置为120秒。

  2. 接受OPTIONS请求处理跨域请求,跨域请求是个较为复杂的主题,您可以参考此链接来了解更多关于跨域请求的内容。

完成代码编写后,我们需要进行一次测试以保证代码的正确运行,在此处我选择使用Postman作为调试工具,您可以选择其他工具进行调试。

首先,启动wrangler的开发功能,使用wrangler dev启动测试环境。使用Postman向http://localhost:8787发送PUT请求,要求body符合上述数据结构。

Postman截图如下:
postmandev

wrangler终端输出如下
wranglerdev

通过Postman或wrangler控制台输出,我们可以判断此段代码是可以正

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WongSSH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值