主页 > imtoken下载中心 > 以太坊区块链如何保证Asp.Net Core的API安全(下)

以太坊区块链如何保证Asp.Net Core的API安全(下)

imtoken下载中心 2023-05-07 06:34:15

正如我们所说以太坊api文档,我们的 DApp 是一个简单的 HTML/ES6 客户端。 我们将在 Asp.Net Core 2 之上构建客户端,以利用 IIS Express 和 Visual Studio IDE。 因此 Startup.cs 类中的 Configure 方法将是:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
app.UseDefaultFiles();
app.UseStaticFiles();

使 DApp 成为 NPM 项目并安装使用 ES6 Javascript 标准的先决条件。 这不是强制性的,可以使用您自己的堆栈构建 DApp。

从项目文件夹运行 Powershell 并运行以下 NPM 命令:

npm init
npm install webpack
npm install babel-core babel-loader --save-dev
npm install babel-preset-es2015 --save-dev
npm install babel-preset-stage-0 --save-dev
npm install babel-polyfill --save
npm install babel-runtime --save
npm install babel-plugin-transform-runtime --save-dev

要配置 webpack/babel,请使用以下配置创建一个 webpack.config.js 文件:

var path = require("path");module.exports = {    entry: [        "babel-polyfill",        "./src/main"
    ],    output: {        publicPath: "/js/",        path: path.join(__dirname, "/wwwroot/js/"),        filename: "main.build.js"
    }
};

我们设置了 webpack 构建 src/main.js 文件到 /www/js/main.build.js。

安装以太坊扩展包:

npm install web3
npm install ethereumjs-util

Web3 是一个 javascript 包装器,可简化对以太坊区块链的 JSON RPC 调用。 Ethereumjs-util 提供了一些特定于以太坊的实用程序。 让我们构建一个非常简单的 HTML 页面。 我们需要一个登录按钮和另一个按钮来从我们的 API 层加载一些安全数据:

以太坊和以太币有什么区别_以太坊api文档_sitebihu.com 以太以太坊价格


    
    Ethereum Jwt Client
    

Ethereum Jwt Client

                       Login     
             Request secured data                       
    

DApp 逻辑将驻留在 src/main.js 文件中,正如我们在 webpack.config.js 文件中指定的那样。 src/main.js 文件将是:

let ethUtil = require('ethereumjs-util');let Web3 = require('web3');let coinbase = null;let accessToken = null;let init = () => {    if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
        web3.eth.getCoinbase(function (err, account) {            if (err === null && ethUtil.isValidAddress(account)) {
                coinbase = account;
                eth_account_span.innerHTML = coinbase;
            } else {
                eth_account_span.innerHTML = 'Please unlock your account and refresh the page';                console.error(err);
            }
        });
    } else {

以太坊和以太币有什么区别_sitebihu.com 以太以太坊价格_以太坊api文档

        eth_account_span.innerHTML = 'Please install or unlock Metamask browser plugin or navigate this page with Mist or another web3 browser';     } };let request = obj => {    return new Promise((resolve, reject) => {        let xhr = new XMLHttpRequest();         xhr.open(obj.method || "GET", obj.url);        if (obj.headers) {            Object.keys(obj.headers).forEach(key => {                 xhr.setRequestHeader(key, obj.headers[key]);             });         }         xhr.onload = () => {            if (xhr.status >= 200 && xhr.status < 300) {                 resolve(xhr.response);             } else {                 reject(xhr.statusText);             }         };         xhr.onerror = () => reject(xhr.statusText);         xhr.send(obj.body);     }); }; login_btn.addEventListener('click', (e) => {     e.preventDefault();     login_btn.setAttribute('disabled', 'disabled');     login_btn.innerHTML = 'Please sign the message';    let plain = 'Hi, you request a login from client to Eth Jwt Api. Please sign this message. This is not a transaction, is completely free and 100% secure. We\'ll use your signature to prove your ownership over your private key server side.';    let msg = ethUtil.bufferToHex(new Buffer(plain, 'utf8'));    let hash = ethUtil.bufferToHex(ethUtil.keccak256("\x19Ethereum Signed Message:\n" + plain.length + plain));    let from = coinbase;    let params = [msg, from];    let method = 'personal_sign';     web3.currentProvider.sendAsync({         method,         params,        from,

以太坊和以太币有什么区别_sitebihu.com 以太以太坊价格_以太坊api文档

    }, function (err, result) {        if (err || result.error) {             login_btn.removeAttribute('disabled');             login_btn.innerHTML = 'Login';            console.error(err);            return console.error(result.error);         }        console.log({            'signature': result.result,            'msg': msg,            'hash': hash         });         login_btn.innerHTML = 'Requesting token...';        let loginData = {};         loginData.signer = from;         loginData.signature = result.result;         loginData.message = msg;         loginData.hash = hash;         request({            url: 'http://localhost:49443/api/token',            body: JSON.stringify(loginData),            method: 'post',            headers: {                'Authorization': 'Bearer ' + accessToken,                'Content-type': 'application/json'             }         }).then(data => {            var json = JSON.parse(data);             accessToken = json.token;            console.log('access token: ' + accessToken);             login_btn.removeAttribute('disabled');             login_btn.innerHTML = 'Login';         }).catch(error => {            console.error(error);             login_btn.removeAttribute('disabled');             login_btn.innerHTML = 'Login';         });     }); });

sitebihu.com 以太以太坊价格_以太坊api文档_以太坊和以太币有什么区别

load_data_btn.addEventListener('click', (e) => {     e.preventDefault();     request({        url: 'http://localhost:49443/api/values',        headers: {            'Authorization': 'Bearer ' + accessToken         }     }).then(data => {        var json = JSON.parse(data);        for (let i = 0; i < json.length; i++) {             data_list.innerHTML += '
  • ' + json[i] + '
  • ';         }     }).catch(error => {        console.error(err);     }); });window.addEventListener('load', init);

    请注意,web3.personal.sign 将十六进制格式 (0x...) 的纯字符串字节数组作为输入。

    正如我们所说,在服务器端,我们将使用两种不同的方式从签名中恢复公钥:一种是在 JSON RPC 接口中使用 web3.personal.ecrecover(对应 web3.personal.sign); 在另一方面,我们将使用底层的 ecrecover 离线功能。 根据文档,web3.personal.sign 使用底层签名函数对哈希进行签名并为消息添加前缀,因此,为了使用底层 ecrecover 对应关系,我们还需要计算此哈希并将其发送到令牌端点。

    运行这两个应用程序并使用安装了 Metamask 插件的浏览器导航到客户端。 请记住,为了将 src/main.js 文件构建为 js/main.build.js,您需要从 Powershell 运行 webpac 命令。 如果一切正常,客户端将检索 coinbase,您将在页面上看到您的帐户:

    webp

    图片

    如果您现在单击“请求数据”按钮,您将收到 401 的 HTTP 响应。如果您单击“登录”按钮,Metamask 将提示您进行签名:

    webp

    图片

    签名后,处理程序将对令牌端点进行 ajax 调用。 在此阶段,身份验证方法不会检查任何签名,因此端点将始终发出 JWT 令牌。 收到 JWT 令牌后,客户端可以通过 ajax 调用安全端点。 如果您现在单击“请求数据”按钮,您将收到带有数据负载的 HTTP 响应 200:

    webp

    图片

    从签名中检索以太坊帐户

    到目前为止,EthereumJwtApi 是一个简单的 JWT Asp.Net 核心示例,因为它不提供任何有效的身份验证方法。

    TokenController 的关键部分是两个 Authenticate 方法及其从签名中检索以太坊帐户的能力。 为此,您需要安装 Nethereum.Web3 NuGet 包。 Nethereum 是以太坊的 .Net 实现。

    Authenticate 方法只是对 web3.personal.ecrecover 函数进行 JSON RPC 调用:

    sitebihu.com 以太以太坊价格_以太坊和以太币有什么区别_以太坊api文档

    private async Task Authenticate(LoginVM login)
    {
        UserVM user = null;    var client = new RpcClient(new Uri(_config["Nethereum:Geth"])); // Require the RPC endpoint of a Geth node as input eg: http://127.0.0.1:8545
        var signer = await client.SendRequestAsync(new RpcRequest(1, "personal_ecRecover", login.Message, login.Signature));    if (signer.ToLower().Equals(login.Signer.ToLower()))
        {        // read user from DB or create a new one
            // for now we fake a new user
            user = new UserVM { Account = signer, Name = string.Empty, Email = string.Empty };
        }    return user;
    }

    优点:

    web3.personal.sign 是 web3.personal.sign 的对应物,因此您无需担心其底层实现。

    缺点:

    需要你自己的 Geth 节点。 不支持奇偶校验,Infura 不允许对 web3.personal.* 进行 JSON RPC 调用。 Authenticate2 方法展示了另一种方法以太坊api文档,它使用底层 ecrecover 功能的离线实现:

    private async Task Authenticate2(LoginVM login)
    {
        UserVM user = null;    var signer = new Nethereum.Signer.MessageSigner();    var account = signer.EcRecover(login.Hash.HexToByteArray(), login.Signature);    if (account.ToLower().Equals(login.Signer.ToLower()))
        {        // read user from DB or create a new one
            // for now we fake a new user
            user = new UserVM { Account = account, Name = string.Empty, Email = string.Empty };
        }    return user;
    }

    优点:

    不需要 JSON RPC 调用即可工作。 MessageSigner.EcRecover 是 Nethereum 提供的离线功能。

    缺点:

    您需要处理 web3.personal.sign 实现以正确恢复帐户。 出于这个原因,在客户端,我们相应地计算了前缀消息哈希。

    综上所述

    现在您已经掌握了使用以太坊保护 Asp.Net Core 2 API 的项目的基础知识和框架。 只是一些注意事项:

    web3 1.0.0 处于测试阶段,web3.personal.sign 的实现可能会随着时间的推移而改变。 请务必在您可以维护的代码库上使用此身份验证方法。 也许 Infura 决定有一天允许 web3.personal.ecrecover :-)