当谈到构建网络应用时,认证可能是一个主要的头痛问题。开发人员需要决定他们想要实现什么样的安全模式,并以正确的方式来实现。
Magic的前身是Fortmatic,它以快速、无缝、单向集成的网络认证而闻名,现在由于其Magic Auth产品,成为区块链生态系统的主要参与者。
在本教程中,我们将演示如何使用Magic与以太坊,讨论设置一个智能合约,并学习如何在以太坊区块链上使用Magic认证用户。
你可以在这篇文章中找到包含我们创建的项目的公共 repo 的链接。
让我们开始吧!
什么是区块链?
区块链是近五年来搅动互联网的一个热门词汇,简单来说,它是一个分布式数据库,在计算机网络的各个节点之间共享,以数字格式的电子方式存储信息。区块链已被广泛采用,因为它保证了数据记录的真实性和安全性。
区块链最出名的是其在加密货币系统中的关键作用,它维护着安全和去中心化的交易记录。
以太坊是一个流行的、去中心化的开源区块链,具有智能合约功能。在这篇文章中,我们将使用以太坊作为我们互动的区块链。
什么是Magic和Magic Auth?
Magic,最初是Fortmatic,因提供一种无缝的方式将认证整合到你的网络应用程序而广为人知。Magic是一个SDK,可以实现无密码认证,只需几行代码就可以集成到你的应用程序中。
我们在本文中使用的Magic Auth是一个SDK,当它集成到你的应用程序中时,可以使用魔法链接实现无密码的Web2和Web3的上机和认证。在撰写本文时,Magic Auth支持20多个区块链,只需几行代码就可以实现。
什么是web3.js?
web3.js是一个库的集合,允许你使用HTTP、IPC或WebSocket与本地或远程以太坊节点互动。总之,Web3.js是一个库,使我们能够使用JavaScript与以太坊区块链互动。
设置Magic和Web3.js
为了开始在以太坊区块链中使用Magic,我们需要添加一些配置和设置。
首先,创建一个新的目录来放置我们的项目:
mkdir magic-blockchain && cd magic-blockchain
接下来,初始化一个Node.js项目:
npm init -y
现在,我们将安装web3.js库和Magic SDK:
npm install --save web3 magic-sdk@1.0.1
编写我们的智能合约
我们需要创建一个智能合约,以后可以部署到Ethereum区块链上。智能合约是存储在区块链上的程序,在满足预定条件时运行。
我们将创建一个基本的 "你好,世界!"智能合约。创建一个名为helloworld.sol 的新文件,代码如下:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract helloworld {
string public message = "Hello World";
function update(string memory newMessage) public {
message = newMessage;
}
}
编译智能合约
如前所述,我们需要将我们的智能合约部署到Ethereum区块链上。为此,我们需要把它编译成我们可以在区块链上执行的形式。
我们将使用下面的代码,通过获取我们需要的Abi和字节码来帮助我们编译智能合约:
npm i solc@0.8.9
创建一个名为compile.js 的文件,并将下面的代码添加到其中:
const path = require('path');
const fs = require('fs');
const solc = require('solc')
const helloWorldPath = path.resolve(__dirname, '' , 'helloworld.sol');
const file = fs.readFileSync(helloWorldPath).toString();
// Input structure for solidity compiler
var input = {
language: "Solidity",
sources: {
"helloworld.sol": {
content: file,
},
},
settings: {
outputSelection: {
"*": {
"*": ["*"],
},
},
},
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
if(output.errors) {
output.errors.forEach(err => {
console.log(err.formattedMessage);
});
} else {
const bytecode = output.contracts['helloworld.sol'].helloworld.evm.bytecode.object;
const abi = output.contracts['helloworld.sol'].helloworld.abi;
console.log(`bytecode: ${bytecode}`);
console.log(`abi: ${JSON.stringify(abi, null, 2)}`);
}
接下来,我们编译合约,得到我们需要的abi 和bytecode 。运行node compile.js ,并将输出的bytecode 和abi 复制到安全的地方存放。
对于合同的部署,我将使用我已经部署的合同的地址。
用Magic Auth认证用户
如前所述,Magic Auth为所有认证的用户创建了一个以太坊公共地址,然后我们可以用它来认证用户。
让我们创建一个index.html 文件,作为我们将要开发的应用程序的GUI。
为了验证用户进入我们的应用程序,我们将与Magic集成。一旦用户被认证,我们将能够看到Magic为该用户在以太坊区块链上自动创建的账户和公共地址。
在实现这个目标之前,我们首先需要创建一个Magic Auth应用程序,以获得我们在应用程序中需要的密钥。
前往你的Magic仪表板,点击新建应用程序按钮,并输入应用程序的名称。然后,复制PUBLISHABLE API KEY 的内容。

index.html 文件的内容可以实现登录和注销能力,以及与以太坊区块链的初始互动。
<!DOCTYPE html>
<html>
<head>
<title>Magic and Ethereum</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="https://auth.magic.link/sdk"></script>
<script src="https://cdn.jsdelivr.net/npm/web3@1.2.11/dist/web3.min.js"></script>
<script>
/* Configure Ethereum provider */
const magic = new Magic("pk_live_your_own_here", {
network: "rinkeby"
});
const web3 = new Web3(magic.rpcProvider);
const render = async () => {
const isLoggedIn = await magic.user.isLoggedIn();
let authHtml = `
<div class="container">
<h1>Please sign up or login</h1>
<form onsubmit="login(event)">
<input type="email" name="email" required="required" placeholder="Enter your email" />
<button type="submit">Send</button>
</form>
</div>
`;
let userHtml = "";
const target = document.querySelector("#app");
if (isLoggedIn) {
const userMetadata = await magic.user.getMetadata();
const userAddress = (await web3.eth.getAccounts())[0];
const userBalance = web3.utils.fromWei(
await web3.eth.getBalance(userAddress)
);
authHtml = `
<div class="container">
<h1>Current user: ${userMetadata.email}</h1>
<h1>User Address: ${userAddress}</h1>
<h1>Current Balance: ${userBalance} ETH</h1>
<button onclick="logout()">Logout</button>
</div>
`;
userHtml = `
<div class="container">
<h1>Ethereum address</h1>
<div class="info">
<a href="https://rinkeby.etherscan.io/address/${userAddres s}" target="_blank">${userAddress}</a>
</div>
<h1>Balance</h1>
<div class="info">${userBalance} ETH</div>
</div>
`;
}
target.innerHTML = authHtml + userHtml
};
const login = async e => {
e.preventDefault();
const email = new FormData(e.target).get("email");
if (email) {
await magic.auth.loginWithMagicLink({ email });
render();
}
};
const logout = async () => {
await magic.user.logout();
render();
};
</script>
</head>
<body onload="render()">
<div id="app">
<div class="container">Loading...</div>
</div>
</body>
</html>

在用户认证后,我们向他们展示一些细节,以确保一切运作良好:

写入区块链
在用户登录后,他们可以通过Magic与区块链互动。为了测试这一点,我们将通过写到区块链来更新合约中的消息属性。
我们将简单地调用合同中的update 方法并传入新的消息。让我们更新一下index.html 文件:
const contractABI = 'theabi';
let contractAddress = "0x83d2F577E2c4D056864543a62B8638bFA0ebaAD6";
let userHtml = "";
let contractHtml = "";
if (isLoggedIn) {
let contract = new web3.eth.Contract(
JSON.parse(contractABI),
contractAddress
);
const currentMessage = await contract.methods.message().call();
contractHtml = `
<div class="container">
<h1>Smart Contract</h1>
<div class="info">
<a href="https://rinkeby.etherscan.io/address/${contractAddress}" target="_blank">${contractAddress}</a>
</div>
<h1>Message</h1>
<div class="info">${currentMessage}</div>
<form onsubmit="update(event)">
<input type="text" name="new-message" class="full-width" required="required" placeholder="New Message" />
<button id="btn-update-msg" type="submit">Update Message</button>
</form>
</div>
`;
}
target.innerHTML = authHtml + userHtml + contractHtml
接下来,我们添加update 方法,它只是使用Magic提供的第一个公共Ethereum账户来发送对合同的update 方法的调用:
const update = async e => {
e.preventDefault();
const newMessage = new FormData(e.target).get("new-message");
if (newMessage) {
const btnUpdateMsg = document.getElementById("btn-update-msg");
btnUpdateMsg.disabled = true;
btnUpdateMsg.innerText = "Updating...";
const fromAddress = (await web3.eth.getAccounts())[0];
const contract = new web3.eth.Contract(
JSON.parse(contractABI),
contractAddress
);
const receipt = await contract.methods
.update(newMessage)
.send({ from: fromAddress });
console.log("Completed:", receipt);
render();
}
};
我们现在有了一个新的界面,如下图所示:

一旦用户输入一个新的消息,将启动一个新的交易来更新消息属性。
请记住,我们需要向用于与区块链互动的账户添加测试用的以太币。要做到这一点,请到Rinkeby Ether Faucet去。在账户中获得一些以太坊后,刷新页面,这样变化就会被反映出来。

接下来,用户通过插入一个新的信息来更新信息。这将需要一些时间,因为它需要与Rinkeby网络上运行的以太坊区块链互动。一旦完成,它应该重新渲染页面,新的合同信息将被显示:

通过点击部署的智能合约的链接,前往Rinkeby,以验证我们可以看到部署该合约的交易和更新消息的交易:

这个更新从我们用来进行更新的账户中抽取一些气体费用。如果我们检查我们当前的余额,我们会看到所需的乙醚被扣除了:

总结
在这篇文章中,我们了解了Magic以及它如何使用web3.js JavaScript库与以太坊区块链整合。
希望你喜欢这篇文章,并对Magic给区块链开发者创造安全、去中心化的应用程序的机会感到兴奋。谢谢你的阅读!