當前位置:
首頁 > 最新 > 使用Node、Coinbase、比特幣和Okta構建自己的結賬服務

使用Node、Coinbase、比特幣和Okta構建自己的結賬服務

看到Node.js、Coinbase、比特幣和Okta可以協同工作,允許您使用每個人最喜歡的加密貨幣創建一個安全的invoicing服務。

我在2011年加入了比特幣。從那以後,我一直對加密貨幣很感興趣,並且一直對它們感興趣。多年來,我還建立了幾個比特幣項目(一個信息網站,一個電子商務網站,還有其他一些),以幫助推廣加密貨幣的使用(同時還有一些樂趣)。

在世界上任何地方,只要沒有中間人,就可以隨時隨地發送和接收金錢,這一想法對很多人來說都很有吸引力。

今天,我認為構建一個小型的web結賬門戶(類似於FreshBooks,但不那麼複雜),可以讓您輕鬆地通過電子郵件向客戶開具發票並收取比特幣付款,這將是一件很有趣的事情。

然後,客戶可以使用當地貨幣或比特幣(如果有的話)支付他們的發票。最後,你將能夠管理和支付你的客戶,並接受比特幣支付。

我自己做了一些諮詢工作,將來也會用到它。

PS:如果你想跳過這篇文章直接去看代碼,那就去吧!我使用的節點。js,表達。和Coinbase為應用提供動力。

從Coinbase、Okta和Node.js開始。

在我向您介紹構建應用程序之前,您需要做一些事情。

您需要創建一個Coinbase帳戶。Coinbase是美國最大、最受歡迎的比特幣交易平台。它允許你很容易地開始使用比特幣而無需安裝軟體,學習很多東西等等。

您還需要創建一個Okta開發人員帳戶。Okta是一個API服務,允許您創建用戶帳戶,並為您的web應用程序、移動應用程序和API服務執行簡單的身份驗證和授權。

最後,需要有節點。在你的電腦上安裝js,準備做一些編碼!>:)

設置Coinbase

要從不同的客戶端發送發票和請求資金,您需要首先生成一個具有適當許可權的Coinbase API密鑰。

Coinbase有一個擴展的API,您可以使用它來做一些事情:其中之一是發送需要錢的發票。要做到這一點,您需要訪問Coinbase API管理頁面,然後單擊按鈕創建一個新的API密鑰。

當您看到彈出式模式提示您使用許可權時,請使用下面的設置:

你在這裡做的是請求API許可:

查看不同的Coinbase帳戶(錢包:帳戶:閱讀)

查看你以前的交易(錢包:交易:閱讀)

創建新的事務請求的錢(錢包:事務:請求)

一旦您完成了密鑰的創建,您就可以看到API密匙和API的秘密值了。把這些抄下來,以後你會用到的。

設置Okta

現在您的Coinbase帳戶已經準備好使用,您需要設置Okta帳戶。這是您將使用的保護門戶的方法,因此只有您可以訪問它。

登錄到您的Okta儀錶板,並複製您在頁面右上角看到的Org URL值。稍後您將需要此值。它看起來是這樣的:

接下來需要創建一個新的Okta應用程序。使用Okta,您可以為您可能擁有的許多應用程序管理用戶。

為此,單擊「大應用程序」菜單項並單擊「添加應用程序」。然後,當您被提示時,選擇Web應用程序選項。這告訴Okta,您正在構建一個web應用程序(例如,不是一個API服務)。在幕後,Okta使用這些信息將您的應用程序設置為適當類型的OAuth 2.0和OpenID連接。

現在,您將看到一個請求您定義應用程序設置的頁面。使用下面的值:

這些設置基本上告訴Okta您的web應用程序將在何處運行(本例中是本地應用程序),以及應用何種安全規則。

一旦您完成了創建應用程序的工作,您就會被帶到您的設置頁面,以獲得這個新創建的應用程序。您需要複製兩個值,您的客戶端ID和客戶端機密。稍後將需要這些。

這些憑據將用於與Okta進行安全通信,以便稍後驗證自己進入web門戶。

克隆項目

現在我們已經做了一些無聊的事情,讓我們看看一些代碼。

您可以從我的GitHub存儲庫本地克隆項目:

$ git clone https://github.com/oktadeveloper/crypto-invoicer

或者你可以把這個項目交給你自己的GitHub賬戶,然後在本地克隆。這可能使您在接下來的操作中更容易地進行更改並使用代碼。

通過本文的其餘部分,我將假定您在克隆/分叉項目目錄中工作。

設置您的憑證

現在,讓我們使用前面收集的憑證,並將它們定義為用於存儲這些敏感值的環境變數。

為此,您需要創建一個名為的文件。env看起來是這樣的:

# .env

export OKTA_ISSUER_URI=https://xxx/oauth2/default

export OKTA_CLIENT_ID=xxx

export OKTA_CLIENT_SECRET=xxx

export REDIRECT_URI=http://localhost:3000/authorization-code/callback

export PORT=3000

export SECRET=xxx

export COINBASE_APIKEY_ID=xxx

export COINBASE_APIKEY_SECRET=xxx

在你看到xxx佔位符的地方替換你的憑證:

應該將okta_addreer_uri設置為您之前複製的Org URL值的值,並將其放置到URL中。最終的URL應該看起來像https://dev-dev-111464.oktapreview.com/oauth2/default。

OKTA_CLIENT_ID和OKTA_CLIENT_SECRET是您在創建Okta應用程序時生成的應用程序憑證。

REDIRECT_URI是一個硬編碼的URL,它將作為身份驗證流的一部分使用。不僅僅是這樣。

埠是你運行webserver的HTTP埠。3000是節點的標準。js應用

秘密應該是你定義的一個長而隨機的字元串。這用於保護您的HTTP會話,並保證您的身份驗證數據安全。我喜歡在鍵盤上敲擊一兩秒鐘來產生這些聲音。

COINBASE_APIKEY_ID和COINBASE_APIKEY_SECRET是您的Coinbase API憑證。

一旦定義了這些設置,就需要告訴終端使用這些變數。要做到這一點,如果您使用的是標準的Linux/Mac/BSD終端,您可以運行以下命令:

$ source .env

源命令將告訴您的shell將在該文件中定義的變數,並使它們可用到終端,以便稍後在您的程序中使用。

如果你在使用Windows,你需要做一些不同的事情。

安裝依賴關係

現在已經完成了安裝,使用npm,節點安裝所有項目依賴項。js包管理器:

$ npm install

這個命令將通過分析包來安裝所有依賴包。json和package-lock。項目目錄中的json文件。

在這些依賴關係中,有一些有趣的:

express是用於構建應用程序的web框架。

Coinbase -node是官方支持的Coinbase開發庫,您將使用它與Coinbase API進行交互。

oidc-中間件是由Okta維護的一個流行的OpenID連接中間件,它負責處理節點的用戶身份驗證和授權。js應用

構建前端

公平警告:我不是一個優秀的前端開發人員。我更像是伺服器端的開發人員。

在啟動新項目時,我喜歡做的第一件事就是快速定義前端視圖。這部分對我來說比較困難,所以我喜歡把它提前。

如果您查看一下視圖目錄,您會注意到只有三個文件:base。哈巴狗,指數。哈巴狗,dashboard.pug。這三個視圖渲染整個網站。

base.pug是另兩個模板擴展的共享基模板。稍後再講這個。

ndex.html 是站點的主頁。

dashboard.pug i是站點的儀錶板視圖。

我使用pug模板語言定義了這些HTML視圖。這使您可以在不使用所有結束標記的情況下編寫HTML,並允許使用空格來推斷結構。

base.pug pug模板提供了其他兩個視圖擴展的通用HTML。這將防止您需要複製在一個或多個頁面之間共享的HTML。

以下是base.pug模板如下:

doctype html

html(lang="en")

head

meta(charset="utf-8")

meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no")

link(rel="stylesheet", href="https://bootswatch.com/4/sketchy/bootstrap.min.css")

link(rel="stylesheet", href="/static/css/style.css")

body

.container

block body

script(src="https://code.jquery.com/jquery-3.2.1.slim.min.js", integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN", crossorigin="anonymous")

script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js", integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh", crossorigin="anonymous")

script(src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js", integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ", crossorigin="anonymous")

這是一個非常標準的HTML頁面,它使用Bootstrap CSS庫和Sketchy Bootswatch主題。這個主題使整個網站看起來像一個模型。由於這是一個示例應用程序,所以我認為主題是合適的。

ndex.pug視圖也很簡單:

extends base.pug

block body

h1.text-center.head Crypto Invoicer

.row.intro

.col

.col-8

.jumbotron

h2.text-center A Personal Invoicing Portal

p.

This is a personal invoicing portal. Use this portal to bill your clients

for work done using #[a(href="https://www.coinbase.com/") Coinbase]:

accept money in USD or Bitcoin.

p.

If you"re performing work for clients and need a simple way to bill

them, give Crypto Invoicer a try!

p.

Please #[a.btn.btn-primary(href="/login") login] to continue.

.col

這個模板只顯示一個基本的主頁,提示用戶登錄到他們的帳戶繼續:

您需要檢查的最後一個視圖是dashboard.pug視圖。此視圖呈現允許用戶創建和查看其發票的儀錶板頁面。

extends base.pug

block body

script(src="/static/js/sorttable.js")

li.nav-item

a.nav-link.active(href="/") Home

li.nav-item

a.nav-link.active(href="/logout") Logout

h1.text-center Dashboard

h2.create-invoice Create Invoice

.row

.col

.col-6

.jumbotron

if error

p.error #

form.form(method="post")

.form-group

label(for="email") To

input#email.form-control(type="email", placeholder="Client Email", name="email", required=true)

.form-group

label(for="description") Description

input#description.form-control(type="text", placeholder="Description", name="description", required=true)

.form-group

label(for="amount") Amount (USD)

input#amount.form-control(type="number", min="1", step="any", name="amount", required=true)

.col

if transactions

h2 Invoices

thead.thead-dark

tr

td Invoice #

td Date Created

td Completed?

td Client Email

td Description

td Amount (USD)

tbody

each transaction in transactions

tr

td #

td #)}

td #

td #

td #

td $#

這個頁面有點複雜。它做了一些關鍵的事情:

它創建了一個表單,允許用戶向客戶發送發票。此表單需要一些輸入參數:客戶端的電子郵件地址、正在計費的內容的描述,以及最終用於支付客戶賬單的金額(美元)。

它列出了HTML表中可以用JavaScript進行排序的所有過去的發票。為此,您將使用pug來遍歷所有過去的事務對象,並適當地顯示它們的數據。

當你渲染這個頁面時,你會看到發票創建表單:

和…如果你產生任何過去的發票,您將看到下面列出:

您還會注意到,如果單擊一個表格標題,您就能夠按您希望的任何列對所有發票進行排序。

如果你看一下儀錶板。上面的pug模板代碼,您可以看到它是如何工作的:

可排序的JavaScript庫用於在瀏覽器中提供自動的表排序。

Pug用於顯示事務細節。

除了這兩件事之外,頁面的其餘部分都是普通的HTML。沒有什麼特別的!

建立伺服器

現在您已經了解了前端代碼的工作方式,讓我們來看看伺服器端代碼庫。

打開伺服器。js文件在項目文件夾的根目錄中找到,並在下面執行。

進口的依賴

我在伺服器上做的第一件事。js是導入所有節點。運行該應用所需的js依賴性:

"use strict";

const Client = require("coinbase").Client;

const async = require("async");

const bodyParser = require("body-parser");

const express = require("express");

const session = require("express-session");

const ExpressOIDC = require("@okta/oidc-middleware").ExpressOIDC;

沒什麼特別的!在每個應用程序中導入依賴項都是標準的。

定義全局變數

您將在伺服器中注意到的下一件事。js是一段代碼,它定義了一些全局變數:

// Globals

const OKTA_ISSUER_URI = process.env.OKTA_ISSUER_URI;

const OKTA_CLIENT_ID = process.env.OKTA_CLIENT_ID;

const OKTA_CLIENT_SECRET = process.env.OKTA_CLIENT_SECRET;

const REDIRECT_URI = process.env.REDIRECT_URI;

const PORT = process.env.PORT || "3000";

const SECRET = process.env.SECRET;

const client = new Client({

apiKey: process.env.COINBASE_APIKEY_ID,

apiSecret: process.env.COINBASE_APIKEY_SECRET

});

let account;

let transactions;

let app = express();

所有的const定義都相當簡單:它們引入前面設置的環境變數值,並將它們存儲為JavaScript變數,以便可以輕鬆引用它們。

客戶端變數定義了一個新的Coinbase API客戶端(稍後用於與Coinbase API進行通信)。

帳戶變數表示一個Coinbase帳戶對象。在Coinbase中,你可以擁有任意數量的「賬戶」:比特幣錢包、美元錢包等。你可以在這些賬戶之間轉賬,就像在普通銀行的支票賬戶一樣。在稍後執行開發票時,您需要知道您想要發出請求的Coinbase帳戶,這決定了您如何收到錢。

事務變數將是我們在Coinbase API中可用的所有最近的發票事務的內存緩存。這是稍後在呈現儀錶板頁面時將使用的內容:我們將存儲事務的緩存,以避免在每個頁面負載上對Coinbase進行API調用。

最後,您將注意到應用程序變數。這是標準快車。js約定:創建一個應用程序對象,然後使用它啟動web伺服器。

配置應用程序設置和中間件。

一旦定義了全局變數,接下來要做的就是定義應用程序設置和中間件。

有一段代碼注釋包含這兩個功能塊:

// App settings

app.set("view engine", "pug");

// App middleware

app.use("/static", express.static("static"));

app.use(session({

cookie: { httpOnly: true },

secret: SECRET

}));

// Authentication

let oidc = new ExpressOIDC({

issuer: OKTA_ISSUER_URI,

client_id: OKTA_CLIENT_ID,

client_secret: OKTA_CLIENT_SECRET,

redirect_uri: REDIRECT_URI,

routes: { callback: { defaultRedirect: "/dashboard" } },

scope: "openid profile"

});

app.use(oidc.router);

這裡只有一個實際的應用程序設置:app.set(「視圖引擎」,「pug」);它所做的只是在呈現視圖時告訴Express使用pug模板引擎。

下面是中間件定義。

第一個定義的中間件是express.static。此中間件配置為從項目文件夾根目錄的靜態目錄中服務靜態資產(css、圖像、javascript)。該定義告訴Express,任何以/static開頭的請求都應該被路由到該文件夾,並自動返回存在的任何文件。

這可能是檢查靜態文件夾的好時機,看看裡面有什麼。只有兩個文件:

一個風格。包含一些定製樣式的css文件。

sorttable。js腳本,在我們的前端使用,使我們的HTML表格可排序。

接下來,您將看到定義的express-session中間件。這個中間件所做的是配置Express來存儲cookie中的敏感用戶信息(這是存儲身份驗證數據的最安全方法)。當您稍後通過Okta登錄到網站時,您的身份驗證信息將存儲在這些由該庫管理的cookie中。

注意:初始化會話庫時使用的秘密變數非常重要。你之前定義的這個長而隨機的字元串是保證你的餅乾不受干擾的原因。如果這個值被公開泄露(在GitHub上等等),那將是一場安全災難。所有基於cookie的系統都需要一個秘密密鑰來用於密碼驗證cookie。

您將看到的最後一個中間件是oidc-中間件。這有點複雜,因為它在後台處理大量的魔術,並且在應用程序工作中實現所有的身份驗證邏輯。

這種中間件的工作方式是完全支持您的應用程序使用OpenID Connect (OIDC)進行身份驗證。當您定義新的ExpressOIDC並給出您的Okta配置信息時,它會構建一個OIDC對象,它會記住您的所有應用程序規則:您的應用程序運行的是什麼URL,在用戶登錄後在哪裡重定向用戶,以及您的秘密應用程序密鑰是什麼等等。

一旦創建了這個新對象,它就包含一個Express router對象,然後使用app.use(oidc.router)來啟用它。調用。這一行記錄了幕後的一些神奇的路線:主要的一個是/登錄。

當這行代碼被執行時,任何請求/登錄都會將您重定向到您的專用登錄頁面(由Okta託管),並提示您登錄到應用程序。一旦用戶登錄,他們將被重定向回您的節點。js應用程序,它們將在那裡登錄,並能夠訪問儀錶板頁面。

定義助手

讓我們跳到伺服器的底部。js文件現在看一下updateTransactions函數:

// Helpers

function updateTransactions(cb) {

transactions = [];

let pagination = null;

async.doWhilst(

function(callback) {

account.getTransactions(pagination, (err, txns, page) => {

if (err) {

return callback(err);

}

pagination = page.next_uri ? page : false;

txns.forEach(txn => {

if (txn.type === "request") {

transactions.push(txn);

}

});

callback();

});

},

function() {

return pagination ? true: false;

},

function(err) {

if (err) {

return cb(err);

}

cb(null, transactions);

}

);

}

這個helper函數的目的是構建一個內存中緩存的Coinbase事務。

每當您從客戶端請求資金並向他們發送發票時,Coinbase會創建一個事務性記錄。有許多不同類型的事務,Coinbase日誌,因此這個函數做的是遍歷所有可用的事務,只刪除與發票相關的事務,然後將它們存儲在全局事務數組變數中以供以後使用。

這裡的想法是,每次顯示指示板,而不是與Coinbase API對話,並實時執行這個邏輯,應用程序將簡單地從緩存中提取最新的事務列表。

在這個函數中,我使用async庫執行一個do-while循環:

與Coinbase API對話並請求一個事務列表。

嘗試確定是否有更多的事務「頁」進行遍歷(因為可能有許多事務,可能需要許多請求到Coinbase API來檢索它們)

只篩選「請求」類型的事務,因為這是該應用程序生成的「請求」貨幣事務。

將它們存儲在全局事務數組中,供以後使用。

定義啟動工作

接下來要做的是定義每次該節點需要運行的作業。js伺服器啟動時。

如果您查看一下startup jobs代碼塊,您就會明白我的意思:

// Startup jobs

client.getAccounts({}, (err, accounts) => {

if (err) {

console.error(err);

}

accounts.forEach(acct => {

if (acct.primary) {

account = acct;

console.log("Downloading initial list of transactions.");

updateTransactions(err => {

if (err) {

console.error(err);

}

});

}

});

});

這段代碼的作用是:

使用Coinbase API列出所有帳戶(這些是您可以在Coinbase中存儲資金的地方)

查看每個賬戶,直到找到主賬戶(這通常是你用來存儲比特幣的比特幣錢包)

將全局帳戶變數設置為這個值。

然後,一旦找到了適當的帳戶對象,此代碼將執行前面定義的updatetransaction helper函數,以構建事務的初始內存緩存。

這樣,在web伺服器開始運行所有事務數據之後不久,就可以進行查詢了。

定義伺服器管理代碼

在伺服器的底部。js文件你會看到一些東西:

// Cron jobs

setInterval(() => {

updateTransactions(err => {

if (err) {

console.error(err);

}

})

}, 1000 * 60 * 60);

// Server management

oidc.on("ready", () => {

app.listen(PORT);

});

oidc.on("error", err => {

console.error(err);

});

setInterval()調用實質上告訴這個節點。js進程每小時更新一次事務數據緩存(以毫秒為單位)。這樣,所有的事務信息將最多一個小時。

最後,一旦認證庫完成了準備工作,Express應用程序本身就會啟動。

注意:在OIDC庫發出「就緒」事件之前,不要運行web伺服器(app.listen(PORT)),這很重要。這可能會導致奇怪的安全邊界情況,如果用戶在OIDC庫完成配置之前發出請求,那麼在您的網站上請求保護頁面的用戶會遇到錯誤。

創建路線

現在我們已經完成了伺服器的其餘部分。js代碼,讓我們看一下我們之前跳過的最後一部分(路由):

// App routes

app.get("/", (req, res) => {

res.render("index");

});

app.get("/dashboard", oidc.ensureAuthenticated(), (req, res) => {

res.render("dashboard", { transactions: transactions });

});

app.post("/dashboard", oidc.ensureAuthenticated(), bodyParser.urlencoded(), (req, res) => {

account.requestMoney({

currency: "USD",

}, (err, txn) => {

if (err) {

console.error(err);

return res.render("dashboard", { error: err });

}

updateTransactions((err, transactions) => {

if (err) {

console.error(err);

return res.render("dashboard", { error: err.message });

}

return res.render("dashboard", { transactions: transactions })

});

});

});

app.get("/logout", (req, res) => {

req.logout();

res.redirect("/");

});

第一個路徑只顯示站點的主頁。因為我們所需要的是顯示一個簡單的模板,除了呈現頁面之外,我們沒有什麼特別需要做的事情。

get(「/dashboard」)路由是在請求時顯示儀錶板頁面的內容。這裡需要注意的是它使用的附加中間件:oidc.ensureAuthenticated()。此中間件強制用戶在訪問此頁面之前登錄。

如果您嘗試在登錄之前訪問/dashboard頁面,例如,您將被重定向到登錄頁面並強制進行身份驗證。

但是,一旦用戶進行了身份驗證,他們就會被允許進入儀錶板頁面,而這個頁面僅僅是使用事務數據的內存緩存來呈現自己。

post(「/dashboard」)路由是處理髮票的。

當用戶填寫發票表單並單擊「提交」時,該路由將被處理並接收發票數據。然後,它使用Coinbase API與Coinbase對話,並生成適當的資金請求(和電子郵件)。最後,在刷新頁面並顯示新的事務列表之前,該代碼將強制刷新事務數據緩存。

通過在創建每個新發票後強制緩存刷新,這將防止在創建發票後出現的問題,您將不會看到它出現在下面的列表中。

當生成發票和Coinbase發送電子郵件時,客戶端會收到一封類似這樣的郵件:

這很好,因為點擊可以點擊「完成支付」。「按鈕,然後被重定向到Coinbase,在那裡他們可以使用比特幣或者他們的本地貨幣(美元)來完成交易。

拼湊在一起

正如我希望向您展示的,使用Node構建比特幣計價軟體。js可以相當簡單。

Coinbase API提供了很多豐富的功能。與Okta配對,用於身份驗證和幾個開放源碼節點。js庫可以在很短的時間內快速地將複雜的應用程序組合在一起。

如果您對構建您自己的加密貨幣應用程序感興趣,我強烈建議您創建一個Coinbase帳戶,並查看其出色的API文檔。他們有大量的庫和工具可以幫助您以一種有趣且快速的方式構建應用程序。

我還建議創建一個Okta developer帳戶,您可以使用它來為您的web應用程序、移動應用程序和API服務存儲用戶,以及處理身份驗證、授權、OAuth 2.0、OpenID連接、單點登錄等等。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 愛碼農 的精彩文章:

使用Vue構建一個延遲載入路由器和最新的瀏覽器特性
為初學者準備16個部分的語言

TAG:愛碼農 |