当前位置:首页 » 《我的小黑屋》 » 正文

前端和Java验签以太坊钱包签名实现中心化登录

21 人参与  2024年05月01日 13:00  分类 : 《我的小黑屋》  评论

点击全文阅读


引言

相信做过一些dapp项目的小伙伴都知道,当dapp需要和中心化的业务系统交互时,怎么验证登录成了一个问题。要dapp输入登录账户密码就很奇怪,违背了设计初衷,不登录吧,中心化系统又没有安全可言。
故此需要一个特定的动作。只有当钱包持有人授权登录(连接钱包),前端js通过调用特定api加密得到算法,从而传到后台验证签名,从而达到登录效果。

前端js 加密代码(web.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!")           //content = "hgqZgU7IuZM8y1rWUQOaMCbbb2QS39EtNWvLGu9FyDvTTQD/cOiLkgYNy+xGl/oEh/idTY2xNh9Kdpmg+ljgfFnd8R8bOEZ2JH38c4Jlhhm6ypntKdVKgrm9dquk8En4sZw1R/mEh8O7sSQ7kLOBv6Epzme0ZGyXJVWA4accjBo=";          // sing= "0xcb0a1688018b8cd8f0f5dd66647de8bb251772bc4aa64c9ac8ffc37af29299462f0ee7715646b8172e381bdf44ac5970180bbc10d31de1b6ec59a09d620fa8e21b";          //walletAddress = "0x37949e80Aedc7d72CFB3667d092161EA8729Ba49";

java验签

引入pom

  <!--web3j-->        <dependency>            <groupId>org.web3j</groupId>            <artifactId>core</artifactId>            <version>5.0.0</version>        </dependency>        <dependency>            <groupId>org.web3j</groupId>            <artifactId>geth</artifactId>            <version>5.0.0</version>            <exclusions>                <exclusion>                    <groupId>com.squareup.okhttp3</groupId>                    <artifactId>okhttp</artifactId>                </exclusion>            </exclusions>        </dependency>        <dependency>            <groupId>org.web3j</groupId>            <artifactId>abi</artifactId>            <version>5.0.0</version>        </dependency>

为了方便java同学测试,我这里附上 验签代码加密代码,线上只需要验签代码,因为加密代码由前端同学完成了。

import org.web3j.crypto.Credentials;import org.web3j.crypto.Keys;import org.web3j.crypto.Sign;import org.web3j.utils.Numeric;import java.math.BigInteger;import java.security.SignatureException;import java.util.Arrays;/** * @Description: Web3j签名验签 */public class ECRecoverUtil {     public static void main(String[] args) throws SignatureException {        String content = "hgqZgU7IuZM8y1rWUQOaMCbbb2QS39EtNWvLGu9FyDvTTQD/cOiLkgYNy+xGl/oEh/idTY2xNh9Kdpmg+ljgfFnd8R8bOEZ2JH38c4Jlhhm6ypntKdVKgrm9dquk8En4sZw1R/mEh8O7sSQ7kLOBv6Epzme0ZGyXJVWA4accjBo=";        String     sing= "0xcb0a1688018b8cd8f0f5dd66647de8bb251772bc4aa64c9ac8ffc37af29299462f0ee7715646b8172e381bdf44ac5970180bbc10d31de1b6ec59a09d620fa8e21b";        String walletAddress = "0x37949e80Aedc7d72CFB3667d092161EA8729Ba49";        boolean mark = validate(sing,content,walletAddress);        System.out.println(sing);        System.out.println(mark);    }    /**     * 签名     *     * @param content    原文信息     * @param privateKey 私钥     */    public static String signPrefixedMessage(String content, String privateKey) {        // todo 如果验签不成功,就不需要Hash.sha3 直接content.getBytes()就可以了        // 原文信息字节数组//        byte[] contentHashBytes = Hash.sha3(content.getBytes());        byte[] contentHashBytes = content.getBytes();        // 根据私钥获取凭证对象        Credentials credentials = Credentials.create(privateKey);        //        Sign.SignatureData signMessage = Sign.signPrefixedMessage(contentHashBytes, credentials.getEcKeyPair());        byte[] r = signMessage.getR();        byte[] s = signMessage.getS();        byte[] v = signMessage.getV();        byte[] signByte = Arrays.copyOf(r, v.length + r.length + s.length);        System.arraycopy(s, 0, signByte, r.length, s.length);        System.arraycopy(v, 0, signByte, r.length + s.length, v.length);        return Numeric.toHexString(signByte);    }    /**     * 验证签名     *     * @param signature     验签数据     * @param content       原文数据     * @param walletAddress 钱包地址     * @return 结果     */    public static Boolean validate(String signature, String content, String walletAddress) throws SignatureException {        if (content == null) {            return false;        }        // todo 如果验签不成功,就不需要Hash.sha3 直接content.getBytes()就可以了        // 原文字节数组//        byte[] msgHash = Hash.sha3(content.getBytes());        byte[] msgHash = content.getBytes();        // 签名数据        byte[] signatureBytes = Numeric.hexStringToByteArray(signature);        byte v = signatureBytes[64];        if (v < 27) {            v += 27;        }        //通过摘要和签名后的数据,还原公钥        Sign.SignatureData signatureData = new Sign.SignatureData(                v,                Arrays.copyOfRange(signatureBytes, 0, 32),                Arrays.copyOfRange(signatureBytes, 32, 64));        // 签名的前缀消息到密钥        BigInteger publicKey = Sign.signedPrefixedMessageToKey(msgHash, signatureData);        // 得到公钥(私钥对应的钱包地址)        String parseAddress = "0x" + Keys.getAddress(publicKey);        // 将钱包地址进行比对        return parseAddress.equalsIgnoreCase(walletAddress);    }}

点击全文阅读


本文链接:http://zhangshiyu.com/post/102623.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1