npm install ethers
import {ethers} from 'ethers'
const accounts = await ethereum.request({method: 'eth_requestAccounts'});
// 获取钱包地址
this.form.address = accounts[0]
console.log("accounts:" + this.address)
const provider = new ethers.BrowserProvider(window.ethereum)
//签名
const signer = await provider.getSigner()
const signature = await signer.signMessage(this.form.address)
console.log("signature:" + signature);
ethers.verifyMessage(nonce, signature) 在后端的实现
Java 后端项目 maven导入web3j
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>4.5.16</version>
</dependency>
Java main方法示例代码
import org.web3j.crypto.ECDSASignature;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.utils.Numeric;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class SignInWithEthereum {
public static void main(String[] args) {
String address = "0x4adbe2009cff6a1e9d280d28815c49e91b8ebad0";
String nonce = "3618473";
String signature = "0x9a38fb504315869609ef2e948b1a80f670e6ff725d16b5ae443b118eb2d108bc3c659c2417d96bbff240b44d4f1078fde73b72f83cc71e4e726640bc19a9c2a91c";
String MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
try {
String digest = Hash.sha3(
Numeric.toHexStringNoPrefix(
(MESSAGE_PREFIX + nonce.length() + nonce).getBytes(StandardCharsets.UTF_8)));
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
byte[] r = (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64);
Sign.SignatureData signatureData = new Sign.SignatureData(v, r, s);
int header = 0;
for (byte b : signatureData.getV()) {
header = (header << 8) + (b & 0xFF);
}
if (header < 27 || header > 34) {
System.out.println("false");
}
int recId = header - 27;
BigInteger key = Sign.recoverFromSignature(
recId,
new ECDSASignature(
new BigInteger(1, signatureData.getR()), new BigInteger(1, signatureData.getS())),
Numeric.hexStringToByteArray(digest));
if (key == null) {
System.out.println("false");
}
String signAddress = ("0x" + Keys.getAddress(key)).trim();
System.out.println("signAddress:" + signAddress);
if (address.toLowerCase().equals(signAddress.toLowerCase())) {
System.out.println("true");
}
} catch (Exception e) {
System.out.println("false");
}
}
}
Java 封装的工具类
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.web3j.crypto.ECDSASignature;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Keys;
import org.web3j.crypto.Sign;
import org.web3j.crypto.Sign.SignatureData;
import org.web3j.utils.Numeric;
public class EthersUtils {
private static final String MESSAGE_PREFIX = "\u0019Ethereum Signed Message:\n";
public static String verifyMessage(String message, String signature) {
return EthersUtils.recoverAddress(EthersUtils.hashMessage(message), signature);
}
public static String hashMessage(String message) {
return Hash.sha3(
Numeric.toHexStringNoPrefix(
(EthersUtils.MESSAGE_PREFIX + message.length() + message).getBytes(StandardCharsets.UTF_8)));
}
public static String recoverAddress(String digest, String signature) {
SignatureData signatureData = EthersUtils.getSignatureData(signature);
int header = 0;
for (byte b : signatureData.getV()) {
header = (header << 8) + (b & 0xFF);
}
if (header < 27 || header > 34) {
return null;
}
int recId = header - 27;
BigInteger key = Sign.recoverFromSignature(
recId,
new ECDSASignature(
new BigInteger(1, signatureData.getR()), new BigInteger(1, signatureData.getS())),
Numeric.hexStringToByteArray(digest));
if (key == null) {
return null;
}
return ("0x" + Keys.getAddress(key)).trim();
}
private static SignatureData getSignatureData(String signature) {
byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
byte[] r = (byte[]) Arrays.copyOfRange(signatureBytes, 0, 32);
byte[] s = (byte[]) Arrays.copyOfRange(signatureBytes, 32, 64);
return new SignatureData(v, r, s);
}
}