【前言】
終於要進到後端的部分啦!一樣先來看 Project 分析,這幾天的內容會環繞在第一步**「連動 MetaMask 系統」和第二步「並且得到當前登入者的以太坊地址」**,我研究了很久才終於理解到底該怎麼實作,希望大家可以留下來品味一下!
【(使用者看見的)前端與(後方運作的)後端】
這篇文章的內容我參考來自 MetaMask Docs 的 Ethereum Provider API 以及 Amaury Martiny 的 One-click Login with Blockchain: A MetaMask Tutorial,在文章最下面的參考資料區我都會附上連結。真的非常感謝這些區塊鏈的工程師無私分享自己的智慧結晶!
【Ethereum Provider API】
因為 MetaMask 是一個瀏覽器插件,所以除了可以被當作以太坊錢包使用外,也可以在網頁上藉由每個帳戶擁有獨一無二的公鑰來交易或驗證,以及將 ****MetaMask ****當作登入介面使用。
【Login Flow】
在一個登入授權中,我們主要確認使用者的 publicAddress
確實為其所有,並且確保 nonce
的可行性。此外使用者不需要自己輸入 publicAddress
因為在登入 MetaMask 之後,我們能透過 web3.eth.coinbase
或相關函式來獲取這項資訊。
Click here to install MetaMask
,按下後跳出網頁轉往下載頁面。nonce
。
在資訊安全中,Nonce 是一個在加密通信只能使用一次的數字。在認證協定中,它往往是一個隨機或偽隨機數,以避免重送攻擊。Nonce 也用於串流加密法以確保安全。如果需要使用相同的金鑰加密一個以上的訊息,就需要 Nonce 來確保不同的訊息與該金鑰加密的金鑰流不同。 *節錄自維基百科《Nonce》- https://zh.wikipedia.org/zh-tw/Nonc*e
publicAddress
來確認其 nonce
。
nonce
。進入 Login Flow 的下一步。nonce
需要跳出 MetaMask 的登入介面。呈現 Sign-In Message 並且在使用者登入時(輸入密碼時)呈現 Loading 圖示。authentication
,其為一個包含 signature
和 publicAddress
的物件。authentication
****後會進行數位加密簽證,以確保這個 nonce
是被這個使用者所登入。以此就可以確保 publicAddress
與擁有者的所有權。nonce
。以上登入流的想法來自於以下這張圖,出處為 Amaury Martiny 的 One-click Login with Blockchain: A MetaMask Tutorial。
【MetaMask Extension Check】
今天的內容我想著重在 Login Flow 中的第一步**「檢測使用者是否已經下載 MetaMask Chrome extension」**
首先會使用到 @metamask/onboarding
這個套件,其功能為在使用者跳出頁面下載 MetaMask 的onboarding 結束後,redirect 回到原先頁面。
npm install @metamask/onboarding
import MetaMaskOnboarding from '@metamask/onboarding'
GitHub - MetaMask/metamask-onboarding: A library to help onboard new MetaMask users
準備在 Button 裡面呈現的文字以及 styled-components 的資訊。
const ONBOARD_TEXT = 'Click here to install MetaMask!';
// 當 USER 未下載 **MetaMask Chrome extension**
const CONNECT_TEXT = 'Welcome Back to Dino Club!';
// 當 USER 已下載 **MetaMask Chrome extension**
const CONNECTED_TEXT = 'Connected';
// 當 USER 已經連接到 Ethereum 帳戶
// styled-components
const clrneon = "#36D7B7";
const StyledButton = styled.button`
...
`;
初始化以及 useState
。
export function OnboardingButton() {
const [buttonText, setButtonText] = useState(ONBOARD_TEXT);
// 按鈕要呈現的文字
const [isDisabled, setDisabled] = useState(false);
// 跳出下載頁面的時候要使按鈕無效
const [accounts, setAccounts] = useState([]);
// 之後要用來記錄 使用者的 ethereum 帳號
const onboarding = React.useRef();
...
return (
<StyledButton disabled={isDisabled} onClick={onClick}>
{buttonText}
</StyledButton>
);
}
使用 useEffect
設定 new MetaMaskOnboarding()
跳出 MetaMask Chrome extension 的下載頁面。
export function OnboardingButton() {
...
useEffect(() => {
if (!onboarding.current) {
onboarding.current = new MetaMaskOnboarding();
}
}, []);
...
return (
...
);
}
使用 useEffect
根據當前是否下載的狀況來改變按鈕功能以及呈現的文字。
export function OnboardingButton() {
...
useEffect(() => {
if (MetaMaskOnboarding.isMetaMaskInstalled()) {
if (accounts.length > 0) {
// 在登入之前 acoount 都不會紀錄任何資料,所以長度會是 0
setButtonText(CONNECTED_TEXT);
setDisabled(true);
onboarding.current.stopOnboarding();
} else {
setButtonText(CONNECT_TEXT);
setDisabled(false);
}
}
}, [accounts]);
...
return (
...
);
}
【小結】
到這裡第一步就大功告成啦!這個部份我用了好幾十個小時才成功。不過好在 MetaMask 的 Doc 有提供非常多資源可以使用,所以才能如願做出來。比較不能完全理解的部分在尋找 window
裡面有 ethereum
的元素部件。我會再研究一陣子等有結果再來跟大家分享!
const isMetaMaskInstalled = () => {
//Have to check the ethereum binding on the window object to see if it's installed
const { ethereum } = window;
return Boolean(ethereum && ethereum.isMetaMask);
};
【參考資料】
Introduction | MetaMask Docs
Breaking Change: No Longer Injecting Web3
One-click Login with Blockchain: A MetaMask Tutorial