使用Python验证Metamask签名(以太坊)



我想使用python验证MetaMask中制作的以太坊(ETH(签名。我正在开发一个使用flask作为后台的网站。Javascript代码向后端发送POST请求,其中包含以下3个变量:

{'signature': '0x0293cc0d4eb416ca95349b7e63dc9d1c9a7aab4865b5cd6d6f2c36fb1dce12d34a05039aedf0bc64931a439def451bcf313abbcc72e9172f7fd51ecca30b41dd1b', 'nonce': '6875972781', 'adress': '0x3a806c439805d6e0fdd88a4c98682f86a7111789'}

我的目标是验证签名是否包含nonce(随机整数(并由公共地址签名

我使用javascript使用以太库对nonce进行签名

const ethereum = window.ethereum;
const provider = new ethers.providers.Web3Provider(ethereum)
const signer = provider.getSigner()
var signature = await signer.signMessage(nonce);

我尝试了几个python库,但我无法格式化签名、地址和nonce以使其工作。以下是使用ecdsa库进行的未成功尝试:

vk = ecdsa.VerifyingKey.from_string(bytes.fromhex(address), curve=ecdsa.SECP256k1, hashfunc=sha256) 
vk.verify(bytes.fromhex(hex(signature)), bytes(nonce, 'utf-8'))

我得到以下错误:

ValueError: non-hexadecimal number found in fromhex() arg at position 1

谢谢你的帮助!

使用web3.py,可以使用w3.eth.account.recover_message从签名和数据中恢复地址。之后,你将地址与正确的地址进行比较(小写,因为我认为web3.py会给你小写和大写(

from web3 import Web3
from hexbytes import HexBytes
from eth_account.messages import encode_defunct
w3 = Web3(Web3.HTTPProvider(""))
mesage= encode_defunct(text="6875972781")
address = w3.eth.account.recover_message(mesage,signature=HexBytes("0x0293cc0d4eb416ca95349b7e63dc9d1c9a7aab4865b5cd6d6f2c36fb1dce12d34a05039aedf0bc64931a439def451bcf313abbcc72e9172f7fd51ecca30b41dd1b"))
print(address)

您可以使用JS进行验证,但我建议您希望使用python在后端进行验证。我面临着完全相同的选择,选择了后者。基本上,我创建了两个api,第一个生成消息和nonce,第二个验证签名。

我使用的是FastAPI,但您可以将其模式化为您喜欢的任何框架,如Django。

生成消息:

# ethaccount is the user's wallet included in the body of the request
async def generate_message(ethaccount: str = Body(...)) -> str:
# I save the wallet to cache for reference later
set_cache_address(ethaccount)
# Generate the nonce
nonce = uuid.uuid4()
# Generate the message
message = f'''
Welcome! Sign this message to login to the site. This doesn't cost you
anything and is free of any gas fees.
Nonce:
{nonce}.
'''
return message

Metamask从这里接管。之后验证元任务生成的签名:

from web3.auto import w3
from eth_account.messages import encode_defunct
async def signature(data: dict = Body(...)):     # noqa
# User's signature from metamask passed through the body
sig = data.get('signature')
# The juicy bits. Here I try to verify the signature they sent.
message = encode_defunct(text=data.get('message'))
signed_address = (w3.eth.account.recover_message(message, signature=sig)).lower()
# Same wallet address means same user. I use the cached address here.
if get_cache_address() == signed_address:
# Do what you will
# You can generate the JSON access and refresh tokens here
pass

注意:我已经清理了这段代码,只显示您可能需要的逻辑/方法。我使用的实际代码随着我生成令牌等而变长。

最新更新