iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

All In One NFT Website Development系列 第 14

Day 14【連動 MetaMask - Front-End Request and Fetch】Modern problems require modern solutions

S__50708609.jpg

【前言】
嗨嗨感謝大家願意看到這裡,接下來要說的是前端的呼叫以及資料傳遞。今天的內容大部份都參考來自 Amaury Martiny 的 One-click Login with Blockchain: A MetaMask Tutorial!終於又可以回來用 web3.js 了,果然現代問題還是要用現代手段解決, web3.jsMetaMask@onboarding 是我的好朋友阿!

【Web3.js】
這裡我們會使用到 JavaScript library web3.js 來引用 MetaMask 的相關 api。相關的介紹會在之後再做敘述!

npm install web3

import Web3 from 'web3';

web3.js - Ethereum JavaScript API - web3.js 1.0.0 documentation

【Front-End Request and Fetch】
在這邊首先使用到 fetch 的功能來新增資料,需要注意的是要先在 .env 宣告 REACT_APP_BACKEND_URL=http://localhost:8000/api

const handleSignup = (publicAddress) =>
		fetch(`${process.env.REACT_APP_BACKEND_URL}/users`, {
			body: JSON.stringify({ publicAddress }),
			headers: {
				'Content-Type': 'application/json',
			},
			method: 'POST',
		}).then((response) => response.json());

這裡可以跳出 MetaMask 的登入介面並且顯示登入訊息,在取得 publicAddress 以及 nonce 之後顯示出來。詳細的步驟解釋可以回去看 Day 10 有提到的 Login Flow。

const handleSignMessage = ({ publicAddress, nonce }) => {
    return new Promise((resolve, reject) =>
      web3.personal.sign(
        web3.fromUtf8(`I am signing my one-time nonce: ${nonce}`),
        publicAddress,
        (err, signature) => {
          if (err) return reject(err);
          return resolve({ publicAddress, signature });
        }
      )
    );
  };

authenticate 之中是傳出 publicAddress 以及 signature,這將會在後端轉譯 signature 後比較這兩者是否相同,來判斷是不是登入成功。

const handleAuthenticate = ({ publicAddress, signature }) =>
    fetch(`${process.env.REACT_APP_BACKEND_URL}/auth`, {
      body: JSON.stringify({ publicAddress, signature }),
      headers: {
        'Content-Type': 'application/json'
      },
      method: 'POST'
    }).then(response => response.json());

將以上的函式放入按鈕的函數之中。

const handleClick = async () => {
		...

		const publicAddress = coinbase.toLowerCase();
		setLoading(true);

		// Look if user with current publicAddress is already present on backend
		fetch(
			`${process.env.REACT_APP_BACKEND_URL}/users?publicAddress=${publicAddress}`
		)
			.then((response) => response.json())
			// If yes, retrieve it. If no, create it.
			.then((users) =>
				users.length ? users[0] : handleSignup(publicAddress)
			)
			// Popup MetaMask confirmation modal to sign message
			.then(handleSignMessage)
			// Send signature to backend on the /auth route
			.then(handleAuthenticate)
			// Pass accessToken back to parent component (to save it in localStorage)
			.then(onLoggedIn)
			.catch((err) => {
				window.alert(err);
				setIsLoading(false);
			});
	};

【小結】
這邊我寫的方法還是主要還是由 MetaMask Onboarding 為主,只是我目前還找不到方法在 MetaMask 的登入介面處顯示 personal.signmessage 來告訴使用者當前的 nonce。這是比較可惜的地方,但是在後端的部分還是有紀錄每個人的登入資訊!

直到這裡就暫時結束登入系統的部分啦,接下來要開始學習 web.js 以及 ether.js 了!未來如果有用到相關的功能會隨時回來這邊做修改!

why_do_we_need_a_backend_why_not_just_connect_front_end_to_database.jpg

【參考資料】
One-click Login with Blockchain: A MetaMask Tutorial
Using Fetch - Web APIs | MDN

【在網站內部驗證 MetaMask 並讓使用者登入】
amaurym/login-with-metamask-demo: Demo project for "One-click Login with Blockchain: A MetaMask Tutorial"
Advanced Ethereum Dapp Series - Part 2 - React Hooks for Injected MetaMask, Web3.js and ethers.js
blockchain election dapp || part 2 react connectivity with metamask
MetaMask Tutorial: One-click Login With Blockchain Made Easy


上一篇
Day 13【連動 MetaMask - Back-End Services】這顯然是廠商的疏失
下一篇
Day 15【web3.js】一袋米要扛幾樓
系列文
All In One NFT Website Development30

尚未有邦友留言

立即登入留言