區塊鏈去中心化思想無處不在,比如最近使用個體抗原自檢替代大規模的中心化核酸檢測,就是去中心化思想的落地實踐,避免了大規模聚集導致的交叉感染,提高了檢測效率,本次我們使用Ethereum最新的ethersV5.0以上版本連結去中心化區塊鏈錢包,並且透過後端Golang1.18服務進行驗籤。
在之前的一篇文章:青山不遮,畢竟東流,整合Web3.0身份錢包MetaMask以太坊一鍵登入(Tornado6+Vue.js3)中,我們使用的是ethersV4.0版本連結Metamask錢包,後端使用基於Python3.10的Tornado6.0框架,為了避免同質化,這裡換成Okc錢包,客戶端外掛安裝地址:https://chrome.google.com/webstore/detail/okx-wallet/mcohilncbfahbmgdjkbpemcciiolgcge
前端連結瀏覽器錢包
首先解除安裝Vue2.0專案:
npm uninstall vue-cli -g
這裡node版本要在8.9以上,npm版本要在6以上;
隨後安裝Vue3.0以上版本:
npm install -g @vue/cli
然後安裝pnpm:
npm install -g pnpm
pnpm解決了傳統npm的node_modules依賴困境,主要透過軟連結和硬連結的結合使用,最終達到節省磁碟空間,安裝速度快,嚴格高效等目的,這裡推薦使用pnpm進行包管理。
接著,在當前專案中安裝ethers庫:
pnpm install ethers@5.7.2 --save
注意這裡版本要求v5.0以上。
根據ethers5.4官方文件所述:https://docs.ethers.io/v5/getting-started/#getting-started--connecting-rpc
ethers5.0版本支援非同步async操作,提高了效率,async函式就是使用async關鍵字宣告的函式。它是 AsyncFunction 建構函式的例項,並且其中允許使用 await 關鍵字。async 和 await 關鍵字讓我們可以用一種更簡潔的方式寫出基於 Promise 的非同步行為,而無需刻意地鏈式呼叫 promise。
宣告非同步連結方法:
//連結邏輯
connect:async function(){
},
隨後請求連結當前的區塊鏈錢包,並且非同步獲取公鑰地址:
const provider = new ethers.providers.Web3Provider(window.ethereum);
const accounts = await provider.send("eth_requestAccounts", []);
列印錢包地址:
console.log(accounts);
如圖所示:
這裡已經列印出了okc錢包的公鑰地址,隨後生成簽名:
const signer = provider.getSigner();
var rightnow = (Date.now()/1000).toFixed(0)
console.log(rightnow);
signer.signMessage("Signing in at "+rightnow)
.then((signature) => {
//列印簽名和公鑰
console.log(accounts[0],signature);
});
這裡透過provider物件獲取簽名者物件signer,接著呼叫signMessage方法來進行簽名操作,加簽演算法採用最簡單的字串+時間戳的形式。
前端返回簽名和公鑰地址:
0x5cae6c39a56d99d68e7a20c76da0ec387e34249b
0x1093b6dc7c6ae1340b2ebcf819dac1a7160b69a2abbb14d86a0696bd96d6b36923d5f3f82588f30a9353b327014338f51d4e7a90baa8052791a8017f156b57511c
後端Golang驗籤
驗籤的目的很好理解,如果在連結錢包的一瞬間,客戶端被監聽的其他軟體惡意篡改公鑰地址,那麼很可能會給客戶造成不可挽回的經濟損失,所以暴露在前端的一切資料都需要後端進行校驗,之前我們採用的是Python3.10版本進行驗籤操作:
from web3.auto import w3
from eth_account.messages import defunct_hash_message
import time
public_address = "0x5cae6c39a56d99d68e7a20c76da0ec387e34249b"
signature = "0xc7b06789e6710652d8540487055e0e75918c9c4366ec47c9e7008760df1dedd6506a908f466e448481afed3fe009bbdbfdfa16c28585eff68be54d600083d4251b"
#rightnow = int(time.time())
rightnow = 1670142219
print(rightnow)
original_message = 'Signing in at {}'.format(rightnow)
message_hash = defunct_hash_message(text=original_message)
signer = w3.eth.account.recoverHash(message_hash, signature=signature)
print(signer)
程式返回:
1670142219
0x5cAE6c39A56d99d68e7A20c76da0ec387e34249b
這裡透過簽名反向解析出了公鑰地址,並且和前端獲取的地址保持一致。
下面我們採用Golang1.18版本來驗籤,看看有什麼不一樣,首先安裝Golang1.18,請移步:兔起鶻落全端涵蓋,Go lang1.18入門精煉教程,由白丁入鴻儒,全平臺(Sublime 4)Go lang開發環境搭建EP00
隨後安裝基於Golang的Ethereum庫:
go get github.com/storyicon/sigverify
根據官方文件指引:https://github.com/storyicon/sigverify
構建main.go檔案:
package main
import (
"fmt"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/storyicon/sigverify"
)
func main() {
valid, err := sigverify.VerifyEllipticCurveHexSignatureEx(
ethcommon.HexToAddress("0x5cae6c39a56d99d68e7a20c76da0ec387e34249b"),
[]byte("Signing in at 1670142219"),
"0xc7b06789e6710652d8540487055e0e75918c9c4366ec47c9e7008760df1dedd6506a908f466e448481afed3fe009bbdbfdfa16c28585eff68be54d600083d4251b",
)
fmt.Println(valid, err) // true <nil>
}
這裡sigverify.VerifyEllipticCurveHexSignatureEx方法有三個引數,分別是公鑰地址,簽名字符集以及前端返回的簽名字串,返回值為valid:
➜ mydemo git:(master) ✗ go run "/Users/liuyue/wodfan/work/mydemo/src/mytest.go"
true <nil>
如果驗籤透過會返回布林值:true。
至此,後端驗籤流程就結束了。
結語
總體而言,前端Ethers採用了ES7新語法async/await實現了重大改進,它提供了一種使用同步程式碼樣式非同步連結錢包物件的方式,而且不會阻塞主執行緒,而後端Golang作為編譯型語言驗籤流程反而比解釋型的Python更加簡單方便。