{"content":{"title":"DAPP开发中Web3唤醒MetaMask签名数据+Java校验签名实现去中心化和中心化用户数据的鉴权","body":"        使用场景大多数用在DAPP中调用中心化数据或者操作某些中心化功能的时候通过DAPP调用MetaMask钱包对数据进行签名传递给后台，后台验证签名数据是否是否当前用户钱包地址签名的数据实现鉴权。\r\n###### **一、DAPP端用Web3签名数据**\r\n注：不同的web3版本签名代码有点差异\r\n\r\n**1、0.26版本签名 web3.personal.sign**\r\n\r\n```\r\n//参数1：要签名的数据\r\n//参数2：签名的钱包地址\r\nweb3.personal.sign(web3.fromUtf8(\"Hello Dapp\"), \"0x40141cF4756A72DF8D8f81c1E0c2ad403C127b9E\",(err, res) => {\r\n          console.log(\"签名后的数据：\",res)\r\n          //0x53ea88d24f4ef8cdcc4bcc843912510b065cd6014c453ff61316c4cd75162f0a38f83a2103da028fb8e5181292ba194b0c8aa21a9ddacdf6783ebfa608889d121c\r\n      })\r\n\r\n//web3.eth.sign此签名方法MetaMask会提示未来版本会被移除\r\n```\r\n\r\n**2、1.0版本签名  web3.eth.personal.sign**\r\n\r\n**3、唤醒MetaMask钱包签名数据**\r\n```\r\n签名后数据为：0x53ea88d24f4ef8cdcc4bcc843912510b065cd6014c453ff61316c4cd75162f0a38f83a2103da028fb8e5181292ba194b0c8aa21a9ddacdf6783ebfa608889d121c\r\n```\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/7EfH1yhN637f2ef294c57.png)\r\n###### 二、Java端使用Web3J校验数据\r\n**1、正常校验 true**\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/DSgHEM1W637f2f1b5c154.png)\r\n**2、改变下钱包地址在次校验 false**\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/2baJivaU637f2f325f327.png)\r\n\r\n###### 三、后端源码-来源于github上的源码\r\n**1、web3j包**\r\n\r\n```\r\n    <dependency>\r\n            <groupId>org.web3j</groupId>\r\n            <artifactId>core</artifactId>\r\n            <version>3.6.0</version>\r\n        </dependency>\r\n```\r\n**2、校验源码 **\r\n\r\n```\r\npackage zh.block.manage.common.utils;\r\n\r\nimport org.web3j.crypto.*;\r\nimport org.web3j.utils.Numeric;\r\nimport org.web3j.crypto.Sign.SignatureData;\r\n\r\nimport java.math.BigInteger;\r\nimport java.util.Arrays;\r\n\r\n/**\r\n * 以太坊签名消息校验工具\r\n */\r\npublic class MetaMaskUtil {\r\n    /**\r\n     * 以太坊自定义的签名消息都以以下字符开头\r\n     * 参考 eth_sign in https://github.com/ethereum/wiki/wiki/JSON-RPC\r\n     */\r\n    public static final String PERSONAL_MESSAGE_PREFIX = \"\\u0019Ethereum Signed Message:\\n\";\r\n\r\n    public static void main(String[] args) {\r\n        //签名后的数据\r\n        String signature=\"0x53ea88d24f4ef8cdcc4bcc843912510b065cd6014c453ff61316c4cd75162f0a38f83a2103da028fb8e5181292ba194b0c8aa21a9ddacdf6783ebfa608889d121c\";\r\n        //签名原文\r\n        String message=\"Hello Dapp\";\r\n        //签名的钱包地址\r\n        String address=\"0xc290436b3da897115493a1547B52783c50f0Bef3\";\r\n        Boolean result = validate(signature,message,address);\r\n        System.out.println(result);\r\n    }\r\n    /**\r\n     * 对签名消息，原始消息，账号地址三项信息进行认证，判断签名是否有效\r\n     * @param signature\r\n     * @param message\r\n     * @param address\r\n     * @return\r\n     */\r\n    public static boolean validate(String signature, String message, String address) {\r\n        //参考 eth_sign in https://github.com/ethereum/wiki/wiki/JSON-RPC\r\n        // eth_sign\r\n        // The sign method calculates an Ethereum specific signature with:\r\n        //    sign(keccak256(\"\\x19Ethereum Signed Message:\\n\" + len(message) + message))).\r\n        //\r\n        // By adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature.\r\n        // This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to\r\n        // impersonate the victim.\r\n        String prefix = PERSONAL_MESSAGE_PREFIX + message.length();\r\n        byte[] msgHash = Hash.sha3((prefix + message).getBytes());\r\n\r\n        byte[] signatureBytes = Numeric.hexStringToByteArray(signature);\r\n        byte v = signatureBytes[64];\r\n        if (v < 27) {\r\n            v += 27;\r\n        }\r\n\r\n        SignatureData sd = new SignatureData(\r\n                v,\r\n                Arrays.copyOfRange(signatureBytes, 0, 32),\r\n                Arrays.copyOfRange(signatureBytes, 32, 64));\r\n\r\n        String addressRecovered = null;\r\n        boolean match = false;\r\n\r\n        // Iterate for each possible key to recover\r\n        for (int i = 0; i < 4; i++) {\r\n            BigInteger publicKey = Sign.recoverFromSignature(\r\n                    (byte) i,\r\n                    new ECDSASignature(new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())),\r\n                    msgHash);\r\n\r\n            if (publicKey != null) {\r\n                addressRecovered = \"0x\" + Keys.getAddress(publicKey);\r\n\r\n                if (addressRecovered.equals(address)) {\r\n                    match = true;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n        return match;\r\n    }\r\n}\r\n\r\n```\r\n\r\n![image.png](https://img.learnblockchain.cn/attachments/2022/11/hYQ6cxFH637f2f8a3ea11.png)\r\n学如逆水行舟，不进则退。心似平原跑马，易放难收。全栈工程师是指掌握多种技能，并能利用多种技能独立完成产品的人。 也叫全端工程师(同时具备前端和后台能力)，英文Full Stack engineer。【人工智能】【区块链】【系统/网络/运维】【云计算/大数据】【数据库】【移动开发】【后端开发】【游戏开发】【UI设计】【微服务】【爬虫】【Java】【Go】【C++】【PHP】【Python】【Android/IOS】【HTML/CSS】【JavaScript】【Node】。。。\r\n\r\n欢迎各位大神萌新一起专研分享各行各业技术!\r\n\r\nChain区块链开发社区：593674370"},"author":{"user":"https://learnblockchain.cn/people/12241","address":null},"history":null,"timestamp":1669279652,"version":1}