10

使用 MetaMask 登入第三方網站

 2 years ago
source link: https://www.frank.hk/blog/metamask-login/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用 MetaMask 登入第三方網站

發佈:2021-04-063,117 Views技術類metamaskBlockchain

當我們逐漸邁向 Web3.0 的今天,原本的網站登入需要透過用戶名密碼的方式,現在又多了一個選擇。只要有一個數字貨幣錢包,便可以使用這個錢包作為身分認證的方式,完全不需要記住複雜的用戶名和密碼。

在開始之前,不妨先看看我製作的一個 MetaMask 登入示範: 按此前往

MetaMask 是一個非常出名的數字貨幣錢包,在 Chrome 上可以安裝它的官方 Extension。另外登入頁面需要使用 web3js , 可以在 github 上下載。也可以直接使用 CDN :

1<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>

整個登入流程,包括幾個基本步驟,但其實並不複雜,可以簡單的用下面的圖示來表示。

flow.png
登入流程

(瀏覽器)檢測MetaMask

使用錢包登入的先決條件是用戶必須安裝 MetaMask Extension。因此第一步必須檢測瀏覽器是否已經安裝 MetaMask:

1$(function(){
2 if (window.web3) {
3 // 有安裝 MetaMask
4 } else {
5 alert( '沒有安裝 MetaMask' );

(瀏覽器)連接錢包

檢測到已經安裝 MetaMask 之後,便可以嘗試連接錢包和獲得錢包地址。這個步驟需要用戶授權。

1window.web3 = new Web3(window.web3.currentProvider);
2 ethereum.request({ method: 'eth_requestAccounts' }).then((result) => {
3 address = result[0];
4 alert('錢包連接成功');
5 }).catch((error) => {
6 console.log("error",error);

透過調用 ethereum.request({ method: 'eth_requestAccounts' }) , 可以讓 MetaMask 彈出授權連接錢包的畫面,用戶可以在改畫面選擇想綁定的錢包賬戶。

screen-20210406104830%402x.png
授權連接 MetaMask

當取得用戶授權後,透過回調的 address = result[0]; 便可以取得錢包地址。

(伺服器)取得 nonce

取得錢包地址後,便可以繼續開始登入認證。我們要做的是要確定當前的操作者是這個地址的擁有人。

因為只有這個地址的擁有人才擁有錢包對應的私鑰,因此我們可以透過簽名認證的方式,讓用戶對一段信息使用其錢包的私鑰進行簽名,之後在伺服器端,使用錢包的地址(即公鑰)對簽名信息進行驗證。

首先我們需要取得一個 nonce,即「無意義信息」。這個信息必須要由伺服器端產生,並存儲在記憶體中以便下一步驗證時使用。

例子中我們使用 url: "/api/metamask/nonce/"+address 這個 API 來取得 nonce。

(瀏覽器)對 nonce 進行簽名

在取得了 nonce 之後,便需要用戶使用其私鑰對該 nonce 進行簽名認證。 這一步可以透過調用 window.web3.eth.personal.sign 進行。其中第一個參數是經過 hex 後的待簽名數據,即 nonce, 第二個參數是錢包地址,回調參數則包括簽名結果和簽名後的 signature。

Hexdata 可以透過 window.web3.utils.utf8ToHex( originData ) 來取得。

1var hexData = window.web3.utils.utf8ToHex(nonce);
3window.web3.eth.personal.sign(hexData, address, function(result, signature){
4 console.log(result); // 結果
5 console.log(signature); // Signature

(伺服器)驗證簽名

取得用戶對 nonce 的簽名後,伺服器就可以透過用戶的公鑰(即錢包地址), 對簽名進行驗證,看看 signature 和剛才上一步產生的 nonce 是否匹配,若匹配,則認為用戶是該地址的擁有者,可以授權用戶登入系統。

伺服器對簽名信息的驗證,不同的程式語言做法會不同。這裡以 Java 為例:

1public static final String PERSONAL_MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
3public static boolean validate(String signature, String message, String address) {
4 String prefix = PERSONAL_MESSAGE_PREFIX + message.length();
5 byte[] msgHash = Hash.sha3((prefix + message).getBytes());
6 byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
7 byte v = signatureBytes[64];
8 if (v < 27) {
9 v += 27;
11 Sign.SignatureData sd = new Sign.SignatureData(
13 Arrays.copyOfRange(signatureBytes, 0, 32),
14 Arrays.copyOfRange(signatureBytes, 32, 64));
16 String addressRecovered = null;
17 boolean match = false;
19 // Iterate for each possible key to recover
20 for (int i = 0; i < 4; i++) {
21 BigInteger publicKey = Sign.recoverFromSignature(
22 (byte) i,
23 new ECDSASignature(new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())),
24 msgHash);
26 if (publicKey != null) {
27 addressRecovered = "0x" + Keys.getAddress(publicKey);
29 if (addressRecovered.equals(address)) {
30 match = true;
31 break;
35 return match;

簽名驗證的方法會比較繁瑣。以上的示例代碼是參考這篇文章的做法,其它的語言可以參考驗證邏輯做相應的處理。要注意 MetaMask 簽名的信息會自動包含一個 Prefix,\u0019Ethereum Signed Message:\n<length of message>,這點在驗證時要做同樣的處理。

當伺服器成功驗證瀏覽器傳送過來的地址和 signature 後,便可以認為用戶登入成功,可以進行後續的授權操作。

使用數字貨幣錢包登入,因為需要安裝 extension,目前僅能夠在電腦端進行。暫時無法在手機瀏覽器上運行。要在手機上使用,則必須使用 MetaMask 的手機 App 內建的瀏覽器才可。

技術交流,其他諮詢等,請按此聯絡

訂閱我的網站,接收更新以及其他有趣的消息 😙 。 訂閱不收費,走過路過別錯過。
Subscribe to my website, I will email you if any new posts or interesting stuff available.

如果你喜歡我的內容,請考慮用一杯咖啡支持我一下吧,非常感謝 🥰 。
If you like my contents, please support me via BuyMeCoffee, Thanks a lot.

其它相關文章


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK