[英]How to connect Metamask to Web3J (java)
I am trying to connect my Metamask wallet to my Java Spring-Boot backend.我正在尝试将我的 Metamask 钱包连接到我的 Java Spring-Boot 后端。 I was trying to follow the example here .我试图按照这里的例子。 I am able to autogenerate the nonce and receive the wallet ID without a problem.我能够自动生成随机数并毫无问题地接收钱包 ID。 I am trying to verify the signed nonce from the Wallet on the server to make sure that the sender is indeed who they say they are.我正在尝试验证服务器上钱包的签名随机数,以确保发件人确实是他们所说的人。 However, I am unable to find any documentation on Web3J to do this.但是,我无法在 Web3J 上找到任何文档来执行此操作。
Is web3j not the right package to use for this? web3j 不是用于此目的的正确软件包吗? The example shows how to do the verification on NodeJS based on javascript but I don't find any example on how to do this on Java.该示例显示了如何基于 javascript 在 NodeJS 上进行验证,但我没有找到任何关于如何在 Java 上执行此操作的示例。
My understanding is that the public key is the wallet ID itself and that the message is the nonce signed by the private key of the wallet which is not shared for obvious reasons.我的理解是,公钥是钱包 ID 本身,消息是由钱包私钥签名的随机数,出于明显的原因不共享。 According to this, I would need to "decrypt" the message using the public key and see if the decrypted message is same as the nonce that the backend sent to Metamask to sign.据此,我需要使用公钥“解密”消息,并查看解密的消息是否与后端发送给 Metamask 签名的随机数相同。 Is this correct?这个对吗?
Here is my code to create and send the nonce to UI:这是我创建随机数并将其发送到 UI 的代码:
public User findUserByPublicAddress(String publicWalletId) {
User u = userRepository.findByPublicWalletId(publicWalletId);
if(u == null) {
u = new User("", "", "", null, publicWalletId, "");
String nonce = StringUtil.generateRandomAlphaNumericString();
u.setNonce(nonce);
userRepository.saveAndFlush(u);
}
return u;
}
Here, I see if the user is already in my system and if they are not, then I just create a temporary user with a random nonce generated and saved in the DB.在这里,我查看用户是否已经在我的系统中,如果不是,那么我只需创建一个临时用户,并生成一个随机随机数并将其保存在数据库中。 This nonce is sent to the UI for Metamask to sign.这个 nonce 被发送到 UI 以供 Metamask 签名。 However, I am not sure how to do the verification part of it.但是,我不确定如何进行验证部分。
I was able to figure this out finally.我终于能够弄清楚这一点。 My initial understanding was incorrect.我最初的理解是错误的。 I was not supposed to attempt to decrypt the message to retrieve the nonce.我不应该尝试解密消息以检索随机数。 Rather I needed to use the nonce to see if I can retrieve the public key of the private key used to sign the message and see if that public key retrieved matches the wallet ID.相反,我需要使用 nonce 来查看是否可以检索用于签署消息的私钥的公钥,并查看检索到的公钥是否与钱包 ID 匹配。
Here is a sample code for UI (JavaScript and HTML):这是 UI(JavaScript 和 HTML)的示例代码:
web3.eth.sign(
web3.utils.sha3(nonce),
window.userWalletAddress)
.then((message) => {
console.log(message)
data['message'] = message // BODY
var xmlReq = new XMLHttpRequest();
xmlReq.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
response = this.responseText
console.log(response)
}
};
xmlReq.open("POST", "/api/users/login", true)
xmlReq.setRequestHeader('Content-Type', 'application/json')
xmlReq.send(JSON.stringify(data))
})
The web3.eth.sign() takes the message to be signed and takes the wallet ID that is signing it. web3.eth.sign() 获取要签名的消息并获取正在签名的钱包 ID。 This is then sent to the backend.然后将其发送到后端。 In the backend:在后端:
public User signin(UserLoginDTO loginDetails, HttpServletResponse response) {
try {
// Get the wallet ID and signed message from the body stored in the DTO
String publicWalletId = loginDetails.getPublicWalletId();
String message = loginDetails.getMessage();
// Find the nonce from the DB that was used to sign this message
User user = userRepository.findByPublicWalletId(publicWalletId);
String nonce = user.getNonce();
// Generate the HASH of the Nonce
byte[] nonceHash = Hash.sha3(nonce.getBytes()) // org.web3j.crypto.Hash
// Generate the Signature Data
byte[] signatureBytes = Numeric.hexStringToByteArray(message); // org.web3j.utils.Numeric
byte v = (byte) ((signatureBytes[64] < 27) ? (signatureBytes[64] + 27) : signatureBytes[64]);
byte[] r = Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = Arrays.copyOfRange(signatureBytes, 32, 64);
SignatureData signatureData = new SignatureData(v, r, s); // org.web3j.crypto.Sign.SignatureData
// Generate the 4 possible Public Keys
List<String> recoveredKeys = new ArrayList<>();
for(int i = 0; i < 4; i++) {
BigInteger r = new BigInteger(1, signatureData.getR());
BigInteger s = new BigInteger(1, signatureData.getS());
ECDSASignature ecdsaSignature = new ECDSASignature(r, s);
BigInteger recoveredKey = Sign.recoverFromSignature((byte)i, ecdsaSignature, nonceHash);
if(recoveredKey != null) {
recoveredKeys.add("0x" + Keys.getAddressFromKey(recoveredKey)); // org.web3j.crypto.Keys
}
}
// Check if one of the generated Keys match the public wallet ID.
for(String recoveredKey : recoveredKeys) {
if(recoveredKey.equalsIgnoreCase(publicWalletId)) {
// Add Code here to create the JWT and add that to your HttpServletResponse. Not shown here.
return user;
}
}
throw new CustomException("Message Sign Invalid", HttpStatus.UNAUTHORIZED);
}
catch (Exception ex) {
// Custom Error Handling.
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.