如何使用Java 验证以太坊签名?
场景
在dapp应用中需要用户进行签名某个文本,后台验证这个文本来源于这个账号,然后进行对应的登录操作,返回于服务器交互的token。
代码
js前端工具类
import {ethers,providers} from 'ethers';
class WalletHolder{
provider:providers.Provider;
signer:providers.JsonRpcSigner;
accounts:Array<string>;
constructor(_provider:providers.Provider,_signer:providers.JsonRpcSigner,_accounts:Array<string>) {
this.provider = _provider;
this.signer = _signer;
this.accounts = _accounts;
}
}
export default class WalletUtils{
public static async metamask() : Promise<Array<any>> {
try {
var provider = new ethers.providers.Web3Provider(window['ethereum']);
var accounts = await provider.send("eth_requestAccounts", []);
var signer = await provider.getSigner();
console.log("Account:", await signer.getAddress());
} catch (error) {
return [null,error]
}
return [new WalletHolder(provider,signer,accounts),null];
}
static holder:WalletHolder;
public static get signer() : providers.JsonRpcSigner {
return WalletUtils.holder.signer;
}
public static get provider() : providers.Provider {
return WalletUtils.holder.provider;
}
public static get accounts() : Array<string> {
return WalletUtils.holder.accounts;
}
public static async init(){
const[holder,error] = await WalletUtils.metamask();
if(error){
console.error('init metamask error',error)
return;
}
if(holder instanceof WalletHolder){
WalletUtils.holder = holder;
console.log('init success')
}
}
}
请求签名
if(!WalletUtils.holder){
await WalletUtils.init();
}
const defaultSinger = WalletUtils.signer;
//使用签名及逆行
const message = await defaultSinger.signMessage("areyouok!")
console.log(message)
//0x8143e2b0a387f1e05b5f37c5ffdc88e29962a042d114f3f06df2679f6ce90a310d8d9df46fb595c6ab26fcbcbec9a6407c586956cfd5076f12ce8041024abcfd1c
后台验签方法
static boolean isSignatureValid(final String address, final String signature, final String message) {
log.info("isSignatureValid invoked for Address {} with Signature {} and Message {} ", address, signature,
message);
final String personalMessagePrefix = "\u0019Ethereum Signed Message:\n";
boolean match = false;
final String prefix = personalMessagePrefix + message.length();
final byte[] msgHash = Hash.sha3((prefix + message).getBytes());
final byte[] signatureBytes = Numeric.hexStringToByteArray(signature);
byte v = signatureBytes[64];
if (v < 27) {
v += 27;
}
final Sign.SignatureData sd = new Sign.SignatureData(v,
Arrays.copyOfRange(signatureBytes, 0, 32),
Arrays.copyOfRange(signatureBytes, 32, 64));
String addressRecovered = null;
// Iterate for each possible key to recover
for (int i = 0; i < 4; i++) {
final BigInteger publicKey = Sign.recoverFromSignature((byte) i, new ECDSASignature(
new BigInteger(1, sd.getR()),
new BigInteger(1, sd.getS())), msgHash);
if (publicKey != null) {
addressRecovered = "0x" + Keys.getAddress(publicKey);
if (addressRecovered.equals(address)) {
match = true;
break;
}
}
}
return match;
}
Java代码来源于 stackexchange 依赖用到了 [web3j 4.8.4]