karhal/web3-connect

允许通过以太坊钱包在 symfony 应用中进行登录

安装次数: 3,015

依赖项: 0

建议者: 0

安全: 0

星标: 6

关注者: 1

分支: 1

开放问题: 7

类型:symfony-bundle


README

Depfu codecov

Web3 钱包 Connect 包

描述

此 Symfony 包允许用户通过他们的以太坊钱包进行认证。为此,您只需要让他们用他们的钱包签名一条消息。

此包使用 EIP-4361,旨在与 spruceid/siwe 库一起工作

为什么?

您的钱包允许您通过您的以太坊账户连接到任何去中心化应用程序。这就像一个您可以在许多 dapp 上使用的登录凭证。此包旨在将此功能带给每个 Symfony 网站。

入门

安装

composer require karhal/web3-connect
<?php

//config/bundles.php

return [
    //... ,
    Karhal\Web3ConnectBundle\Web3ConnectBundle::class => ['all' => true],
];

配置

config/packages/web3_connect.yaml

wallet_connect:
  user_class: App\Entity\User
  jwt_secret: MySecretPhrase

config/packages/security.yaml

security:
    #...
    providers:
        #...
        web3_user_provider:
            entity:
                class: App\Entity\User
                property: walletAddress
    firewalls:
        #...
        web3:
            custom_authenticators:
                - Karhal\Web3ConnectBundle\Security\Web3Authenticator
            provider: web3_user_provider

        main: #...

config/routes.yaml

web3_link:
  resource: "@Web3ConnectBundle/config/routes.yaml"

通过实现 Web3UserInterface 更新表示用户的类的模型

//...
use use Karhal\Web3ConnectBundle\Model\Web3UserInterface;
//...

class User implements Web3UserInterface
{
    //...
    
    #[ORM\Column(type: 'string', nullable: true)]
    private ?string $walletAddress;

    public function getWalletAddress(): string
    {
        return $this->walletAddress;
    }

    public function setWalletAddress(string $wallet)
    {
        $this->walletAddress = $wallet;
    }
}

然后更新您的存储

php bin/console doctrine:mig:diff
php bin/console doctrine:mig:mig

现在您可以开始了

使用

此包提供了一个签名路由来生成要签名的消息。消息签名后,将其与签名的地址一起发送回来。

步骤 1:获取 nonce

在每次签名之前,从后端获取 nonce

    const res = await fetch(`${BACKEND_ADDR}/web3_nonce`, {
    credentials: 'include',
    mode: 'cors',
    headers: {
        'Accept': 'application/json',
    },
});

步骤 2:生成消息

    const message = await createSiweMessage(
        await signer.getAddress(),
        'Sign in with Ethereum to the app.'
    );

步骤 3:发送带有签名的消息

    const res = await fetch(`${BACKEND_ADDR}/web3_verify`, {
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({ message, signature }),
    credentials: 'include',
    method: "POST",
    mode: 'cors',
});

完整的示例(使用 spruceid/siwe-quickstart 示例

import { ethers } from 'ethers';
import { SiweMessage } from 'siwe';

const domain = window.location.host;
const origin = window.location.origin;
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

const BACKEND_ADDR = "http://127.0.0.1:8000";
async function createSiweMessage(address, statement) {
    const res = await fetch(`${BACKEND_ADDR}/web3_nonce`, {
        credentials: 'include',
        mode: 'cors',
        headers: {
            'Accept': 'application/json',
        },
    });
    const message = new SiweMessage({
        domain,
        address,
        statement,
        uri: origin,
        version: '1',
        chainId: '1',
        nonce: (await res.json()).nonce
    });
    return message.prepareMessage();
}

function connectWallet() {
    provider.send('eth_requestAccounts', [])
        .catch(() => console.log('user rejected request'));
}

async function signInWithEthereum() {
    const message = await createSiweMessage(
        await signer.getAddress(),
        'Sign in with Ethereum to the app.'
    );
    const signature = await signer.signMessage(message);

    const res = await fetch(`${BACKEND_ADDR}/web3_verify`, {
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ message, signature }),
        credentials: 'include',
        method: "POST",
        mode: 'cors',
    });
    document.getElementById('infoUser').innerText = 'Welcome '+  (await res.json()).identifier;
}


const connectWalletBtn = document.getElementById('connectWalletBtn');
const siweBtn = document.getElementById('siweBtn');
connectWalletBtn.onclick = connectWallet;
siweBtn.onclick = signInWithEthereum;

该包将验证签名的消息是否属于该地址。如果是,您的存储中将加载地址的所有者作为 JWT 令牌。

响应

{
    "identifier": "foo@bar.com",
    "token": "eyJ0eXs[...]",
    "data": {}
}

步骤 4:访问授权路由

现在,您可以通过在请求的头部添加带有刚刚生成的令牌值的 http_header 来向授权路由发出请求。

    const res = await fetch(`${BACKEND_ADDR}/private_url`, {
    headers: {
        'Accept': 'application/json',
        'X-AUTH-WEB3TOKEN': 'eyJ0eXs[...]'
    },
});

步骤 5:自定义包响应

在返回响应之前,包将触发一个 DataInitializedEvent 事件,提供您可以填充以向前端提供一些额外信息的数组。

您可以通过监听此事件并调用其 setData 方法来添加任何想要的数据。

<?php

namespace App\EventListener;

use Karhal\Web3ConnectBundle\Event\DataInitializedEvent;

class Web3LoginEventListener
{
    public function onWeb3userDataInitialized(DataInitializedEvent $event)
    {
        $event->setData(['foo' => 'bar']);
    }
}

响应

{
    "identifier": "foo@bar.com",
    "token": "eyJ0eXs[...]",
    "data": {
        "foo": "bar"
    }
}

资源

什么是以太坊钱包?

以太坊钱包是允许您与您的以太坊账户交互的应用程序。将其想象成一个没有银行的互联网银行应用程序。您的钱包允许您查看您的余额、发送交易并连接到应用程序。

“不再需要为不同网站记住唯一的密码。不再需要为不同服务创建唯一的电子邮件地址。不再需要担心您与之交互的网站从您那里窃取数据。在互联网上对您的账户进行纯粹的、自有的控制。除了在注册时生成的公钥之外,没有用户名、密码或其他识别信息。”

测试

vendor/bin/phpunit 

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件