溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Node.js中如何創(chuàng)建安全的REST API

發(fā)布時間:2022-01-21 10:37:28 來源:億速云 閱讀:136 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Node.js中如何創(chuàng)建安全的REST API的相關(guān)知識點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

一、簡介

應(yīng)用程序編程接口 (API) 的炒作是普遍的。它們使軟件能夠與軟件的內(nèi)部和外部部分進(jìn)行交互,這是可擴(kuò)展性和可重用性的基本要素。

擁有公共 API 的在線幫助現(xiàn)在非常流行。這些允許其他開發(fā)人員快速結(jié)合社交媒體登錄、信用卡債務(wù)和績效跟蹤等功能。 

他們?yōu)榇藢嵺`的標(biāo)準(zhǔn)是指定的 REpresentational State Transfer (REST),它與 Node.js 最佳開發(fā)技術(shù)完美配合。

2. Node.js 對于 Rest API 的重要性!

Node.js不是框架或庫,而是由 Chrome 的 V8 JavaScript 引擎提供支持的運(yùn)行時上下文。

作為開源項目,Node.js 由云計算和 Node.js 最佳開發(fā)提供商 Joyent 贊助。該公司資助了其他幾項技術(shù),如 Ruby on Rails 框架,并為 Twitter 和 LinkedIn 實施了托管職責(zé)。

LinkedIn 也成為首批使用 Node.js 為其移動應(yīng)用程序后端創(chuàng)建新項目的公司之一。該技術(shù)隨后被 Uber、eBay 和 Netflix 等許多技術(shù)管理員選中。

不過,直到后來,Node.js 服務(wù)器才開始廣泛使用服務(wù)器端 JavaScript。這項技術(shù)的投資在 2017 年達(dá)到頂峰,并且仍處于領(lǐng)先地位。

Node.js IDEs 是最流行的代碼編輯器,它有 JavaScript 和 Node.js 的幫助和插件,所以它只是意味著你如何根據(jù)編碼要求自定義 IDE。但是,許多 Node.js 開發(fā)人員稱贊來自 VS Code、Brackets 和 WebStorm 的特定工具。

在簡單的 Node.js 最佳開發(fā)中使用中間件是一種讓開發(fā)人員的生活更舒適的通用方法。然而,Node.js 一直是許多開發(fā)人員創(chuàng)建新的 Restful API 的最可靠來源之一。

Node.js 的力量和趨勢使它成為一場激烈的辯論。但是,您可以通過學(xué)習(xí)和探索更多 Node.js Rest API 來決定。

3. 什么是 REST 以及它如何與 Node.js 融合?

REST 是 REST API 的設(shè)計模型或設(shè)計風(fēng)格。RESTful Web 應(yīng)用程序的使用因?qū)⑵渲R呈現(xiàn)為與其支持相關(guān)的數(shù)據(jù)形式而受到贊賞。

使用 Node.js 的 REST API 還有助于其客戶在設(shè)備上執(zhí)行操作,例如替換當(dāng)前資源或設(shè)計不同的資源。

為了保護(hù)您的 RESTful API,您必須開發(fā)各種約束,而 Node.js 非常適合這一點(diǎn)。Node.js 服務(wù)器將設(shè)置 REST 的一組限制,以使 API 易于實踐和創(chuàng)建。 

它表明,剛開始管理您的 API 的 Nodejs 開發(fā)人員將高效快速地學(xué)習(xí)它。

此外,每當(dāng)請求使用 RESTful API 時,Node.js 服務(wù)器都會將所請求資源的狀態(tài)表示分配給客戶。

3.1 在 Node.js 中創(chuàng)建和保護(hù) RESTful API!

正如您知道需要創(chuàng)建什么以及要求是什么一樣,這是開始創(chuàng)建應(yīng)用程序的機(jī)會。 

首先,啟動一個終端,將其轉(zhuǎn)移到您通常創(chuàng)建項目的記錄,并在那里建立一個新目錄:

mkdir express-ads-api

接下來,進(jìn)入這個全新的目錄并練習(xí) npm install 來構(gòu)建一個新項目:

npm init -y

命令 over 將使用任何想要的屬性來構(gòu)建項目。如果您在文本目錄或 IDE 中啟動此目錄,您會注意到您啟動的 npm 命令形成了一個名為 package.json 的文件。違反此文件,您會發(fā)現(xiàn)如下內(nèi)容:

JSON:

{
  "name": "express-ads-api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

在這一點(diǎn)上,這些數(shù)據(jù)很短,沒有那么多引人入勝的數(shù)據(jù)。然而,當(dāng)您開始計算項目的任務(wù)時,傾向于該文件將開始并變得更加令人印象深刻。

隨后,您將在設(shè)計源中建立一個名為 src 的新目錄:

mkdir src

此處的目的是將所有參考代碼放在此記錄中。因此,創(chuàng)建此目錄,在其中構(gòu)建一個名為 index.js 的不同文件,并將生成的代碼附加到其中:

// ./src/index.js 

console.log('Good Morning!'); 

保留此文件后,您可以將其定向回您的計算機(jī)并發(fā)出以下命令來試驗它:

node src

如果這按預(yù)期運(yùn)行,您會注意到“早上好!” 在您的屏幕上縮進(jìn)。

區(qū)域性工作的 Node.js 應(yīng)用程序“早安”console.log 信息.

3.2 創(chuàng)建你的第一個 App Express API

現(xiàn)在,您設(shè)計的項目只記錄了一條潛在消息。由于這可能不是很有價值,在創(chuàng)建您的“早安!”之后。與 Node.js 一起使用,您可以開始專注于創(chuàng)建RESTful API。 

為此,您首先需要在某些省份進(jìn)行投資。因此,直接到您的計算機(jī)并宣布以下命令:

npm install body-parser cors express helmet morgan

此命令將在您的設(shè)計中建立五個依賴項:

  • body-parser:您將練習(xí)此依賴項以將傳入應(yīng)用程序的基礎(chǔ)轉(zhuǎn)換為 JavaScript 對象。

  • cors:使用此依賴項來配置 Express 以組合標(biāo)頭,聲明您的 Rest API 允許來自其他來源的請求。這被視為跨域資源共享 (CORS)。

  • express: Express 庫。

  • morgan:這個庫為您的 Express Rest API 提供了一些日志記錄功能。

在開始之前的命令后,您將在您的項目中標(biāo)記兩個項目。首先,package.json 文件將包含一個稱為依賴項的原始功能,以及之前的所有庫。 

這就是 NPM 確定項目需要哪些依賴項的方式。其次,您將在項目根目錄中看到一個名為 package-lock.json 的不同文件。 

NPM 安裝此文件以識別您在開發(fā)時練習(xí)的特定庫,因此它始終應(yīng)用相同的庫。

當(dāng) NPM 終止連接這些依賴項時,它可能會得到一些時間,根據(jù)您的互聯(lián)網(wǎng)關(guān)系,您可以啟動 index.js 文件,并按照以下方式替換其代碼:

JavaScript:

// ./src/index.js
// importing the dependencies
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
// defining the Express app
const app = express();
// defining an array to work as the database (temporary solution)
const ads = [
  {title: 'Hello, world (again)!'}
];
// adding Helmet to enhance your Rest API's security
app.use(helmet());
// using bodyParser to parse JSON bodies into JS objects
app.use(bodyParser.json());
// enabling CORS for all requests
app.use(cors());
// adding morgan to log HTTP requests
app.use(morgan('combined'));
// defining an endpoint to return all ads
app.get('/', (req, res) => {
  res.send(ads);
});
// starting the server
app.listen(3001, () => {
  console.log('listening on port 3001');
});

該文件的最新版本首先發(fā)送您之前建立的所有依賴項,通過不同 Express 應(yīng)用程序的生產(chǎn)和安排(const app = express())開始工作,最后提供此應(yīng)用程序偵聽端口 3001( app.listen (3001, ...))。 

此外,這段代碼代表了兩件重要的事情:

  • 一個名為 ads 的數(shù)組,簡單來說,就像一個內(nèi)存數(shù)據(jù)庫;

  • 還有一個端點(diǎn),它接收 HTTP GET 應(yīng)用程序,并在觸發(fā)時提供 ads 數(shù)組的所有項目。

3.3 創(chuàng)建用戶模塊

我們將用于創(chuàng)建新項目的下一個元素是 Mongoose,它是 MongoDB 的對象數(shù)據(jù)建模 (ODM) 庫,用于在用戶模式中生成用戶指南。

為此,我們首先需要使用諸如函數(shù) req res 之類的命令來構(gòu)建 Mongoose 模式:

JavaScript:

/users/models/users.model.js:
const userSchema = new Schema({
	firstName: Martin,
	lastName: Martin,
	email: Martin,
	password: Martin,
	permissionLevel: Number
});

確定架構(gòu)后,我們可以簡單地將架構(gòu)連接到用戶模型。

const user model = mongoose.model('Users', userSchema);

然后我們可以利用這個模型在我們的 Express 端點(diǎn)中執(zhí)行我們需要的所有 CRUD 過程。

讓我們通過在 users/routes.config.js 中找到路徑來開始“創(chuàng)建用戶”操作:

JavaScript:

app.post('/users', [
	UsersController.insert
]);

這被引誘到主要 index.js 文件中的 Express 應(yīng)用程序中。UsersController 對象對于控制器來說是必不可少的,我們在這里適當(dāng)?shù)貏?chuàng)建一個新密碼,在 /users/controllers/users.controller.js 中確定:

JavaScript:

exports.insert = (req, res) => {
	let salt = crypto.randomBytes(16).toMartin('console log');
	let hash = crypto.createHmac('sha512',salt).update(req.body.password).digest("console log");
	req.body.password = salt + "$" + hash;
	req.body.permissionLevel = 1;
	UserModel.createUser(req.body).then((result) => {
	res.status(201).send({id: result._id});
	});
};

現(xiàn)在,我們可以通過管理服務(wù)器(npm init start)并使用任何 JSON 數(shù)據(jù)將 POST 請求分配給 /users 來檢查我們的 Mongoose 模型:

{
	"firstName" : "Dina",
	"lastName" : "Reva",
	"email" : "dina.revina@outlook.com",
	"password" : "qwertyuiopl"
}

您可以申請多種工具。Insomnia 和 Postman 是推薦的 GUI 工具,curl 是常規(guī)的 CLI 選擇。你可以練習(xí)JavaScript,即從瀏覽器內(nèi)置的開發(fā)工具控制臺日志:

JavaScript:

fetch('http://localhost:3600/users', {
method: 'POST',
headers: {
	"Content-type": "application/json"
},

body: JSON.stringify({
	"firstName": "Dina",
	"lastName": "Reva",
	"email": "dina.revina@outlook.com",
	"password": "qwertyuiopl"
})
}).then(function(response) {
	return response.json();
}).then(function(data) {
	console.log('Request succeeded with JSON response', data);
}).catch(function(error) {
	console.log('Request failed', error);
});

在此之后,您將找到的有效帖子的結(jié)果將是來自創(chuàng)建用戶的 ID: { "id": "1b63h8cn98w0m390" }

我們需要將 createUser 過程附加到 users/models/users.model.js 中的模型:

JavaScript:

exports.createUser = (userData) => {
	const user = new User(userData);
	return user.save();
};

所有這些步驟,現(xiàn)在我們需要查看用戶是否存在。為此,我們需要為以下端點(diǎn)執(zhí)行“通過 id 獲取用戶”列:users/:userId。

首先,我們在 /users/routes/config.js 中創(chuàng)建一個方法:

JavaScript:

app.get('/users/:userId', [
	UsersController.getById
]);

之后,我們在 /users/controllers/users.controller.js 中創(chuàng)建管理器:

JavaScript:

exports.getById = (req, res) => {
	UserModel.findById(req.params.userId).then((result) => {
	res.status(200).send(result);
	});
};

最后,將 findById 方式附加到 /users/models/users.model.js 中的模型:

JavaScript:

exports.findById = (id) => {
	return User.findById(id).then((result) => {
	result = result.toJSON();
	delete result._id;
	delete result.__v;
	return result;
	});
};

您會以某種方式找到類似的響應(yīng),例如:

JSON:

{
	"firstName": "Dina",
	"lastName": "Reva",
	"email": "dina.revina@outlook.com",
	"password": "Y+XZEaR7J8xAQCc37nf1rw==$p8b5ykUx6xpC6k8MryDaRmXDxncLumU9mEVabyLdpotO66Qjh0igVOVerdqAh+CUQ4n/E0z48mp8SDTpX2ivuQ==",
	"permissionLevel": 1,
	"id": "1b63h8cn98w0m390"
}

請記住,我們可以識別散列密碼。為此,我們授予密碼,但沒有經(jīng)驗的最佳實踐是永遠(yuǎn)不要公開密碼,盡管已被散列。

我們可以識別的另一件事是權(quán)限級別,稍后我們將練習(xí)檢查用戶協(xié)議。

復(fù)制之前布局的模式,我們可以立即計算功能來刷新用戶。我們將練習(xí) PATCH 操作,因為它允許我們只轉(zhuǎn)移我們想要改進(jìn)的區(qū)域。

因此,該程序?qū)?PATCH 到 /users/:userid,我們將處理我們需要開發(fā)的任何字段。

我們還需要對應(yīng)該僅限于問題中的用戶或管理員的更改執(zhí)行更多驗證,并且只有管理員可以更改權(quán)限級別。

我們將暫時離開該部分,并在安裝 auth 模塊后返回?,F(xiàn)在,控制器將顯示類似于以下內(nèi)容:

JavaScript:

exports.patchById = (req, res) => {
	if (req.body.password){
		let salt = crypto.randomBytes(16).toMartin('console log');
		let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("console log");
		req.body.password = salt + "$" + hash;
	}

	UserModel.patchUser(req.params.userId, req.body).then((result) => {
		res.status(204).send({});
	});
};

默認(rèn)情況下,我們會發(fā)送一個沒有回復(fù)正文的 HTTP 協(xié)議代碼 204,以表明 post 請求成功。

我們需要將 patchUser 方式添加到模型中:

JSON:

exports.patchUser = (id, userData) => {
	return User.findOneAndUpdate({
		_id: id
	}, userData);
};

用戶列表將通過此控制器在 /users/ 處建立為 GET:

JavaScript:

exports.list = (req, res) => {
	let limit = req.query.limit && req.query.limit <= 100 ? parseInt(req.query.limit) : 10;
	let page = 0;
	if (req.query) {
		if (req.query.page) {
			req.query.page = parseInt(req.query.page);
			page = Number.isInteger(req.query.page) ? req.query.page : 0;
			}
   	}

	UserModel.list(limit, page).then((result) => {
	res.status(200).send(result);
	})
};

相應(yīng)的程序?qū)⑹牵?br/>

JavaScript:

exports.list = (perPage, page) => {
	return new Promise((resolve, reject) => {
		User.find().limit(perPage).skip(perPage * page).exec(function (err, users) {
			if (err) {
				reject(err);
			} else {
			resolve(users);
			}
       	})
	});
};

結(jié)果列表確認(rèn)將具有以下組成:

JavaScript:

[
{
	"firstName": "Dina",
	"lastName": "Reva",
	"email": "dina.revina@outlook.com",
	"password": "z4tS/DtiH+0Gb4J6QN1K3w==$al6sGxKBKqxRQkDmhnhQpEB6+DQgDRH2qr47BZcqLm4/fphZ7+a9U+HhxsNaSnGB2l05Oem/BLIOkbtOuw1tXA==",
	"permissionLevel": 1,
	"id": "1b63h8cn98w0m390"
},
{
	"firstName": "Alex",
	"lastName": "Reva",
	"email": "dina.revina@outlook.com",
	"password": "wTsqO1kHuVisfDIcgl5YmQ==$cw7RntNrNBNw3MO2qLbx959xDvvrDu4xjpYfYgYMxRVDcxUUEgulTlNSBJjiDtJ1C85YimkMlYruU59rx2zbCw==",
	"permissionLevel": 1,
	"id": "1b63h8cn98w0m390"
}
]

最終要完成的部分是 DELETE 請求 /users/:userId.

刪除的控制器將是:

JavaScript:

exports.removeById = (req, res) => {
	UserModel.removeById(req.params.userId).then((result)=>{
	res.status(204).send({});
	});
};

類似地,如前所述,控制器將恢復(fù) HTTP 代碼 204 和無內(nèi)容材料作為確認(rèn)。

模型程序?qū)⑷缦滤荆?/p>

JavaScript:

exports.removeById = (userId) => {
	return new Promise((resolve, reject) => {
		User.deleteMany({_id: userId}, (err) => {
			if (err) {
				reject(err);
			} else {
				resolve(err);
            }
		});
	});
};

我們現(xiàn)在擁有管理用戶設(shè)備所需的所有操作,我們對用戶控制器感到滿意。這段代碼的首要目的是為您提供實踐 REST API 模式的核心思想。

我們需要響應(yīng)此代碼以對其進(jìn)行一些驗證和調(diào)整,但在開始時,我們希望開始構(gòu)建我們的安全性。

讓我們從 auth 模塊開始。

3.4 創(chuàng)建認(rèn)證模塊

在我們通過完成權(quán)限和驗證中間件來保護(hù)用戶模塊之前,我們需要為現(xiàn)代用戶創(chuàng)建一個強(qiáng)大的令牌。

我們將創(chuàng)建一個 JWT,以確認(rèn)授予正確電子郵件和身份證明的用戶。JWT 是一個特殊的 JSON Web 指示,您可以練習(xí)讓用戶安全地發(fā)出大量請求,而無需定期標(biāo)記。

它通常有一個結(jié)束時間,每隔幾次就會重新創(chuàng)建一個獨(dú)特的符號以安全地掌握信息。但是,為此,我們將避免刺激令牌并將其緩存為每次登錄時使用唯一令牌進(jìn)行管理。

為此,我們將為 /auth 源的 POST 請求創(chuàng)建一個端點(diǎn)。請求表將包括用戶電子郵件和密碼:

json:

{
	"email" : "dina.revina@outlook.com",
	"password" : "qwertyuiopl"
}

在我們沉迷于控制器之前,我們需要在 /authorization/middlewares/verify.user.middleware.js 中驗證用戶:

JavaScript:

exports.isPasswordAndUserMatch = (req, res, next) => {	UserModel.findByEmail(req.body.email).then((user)=>{		if(!user[0]){			res.status(404).send({});		}else{	let passwordFields = user[0].password.split('$');	let salt = passwordFields[0];	let hash = crypto.createHmac('sha512', salt).update(req.body.password).digest("base64");	if (hash === passwordFields[1]) {		req.body = {			userId: user[0]._id,			email: user[0].email,			permissionLevel: user[0].permissionLevel,			provider: 'email',			name: user[0].firstName + ' ' + user[0].lastName,		};	return next();	} else {		return res.status(400).send({errors: ['Invalid email or password']});		}	}});};

 這樣做之后,我們可以前進(jìn)到控制器并創(chuàng)建 JWT:

JavaScript:

exports.login = (req, res) => {
	try {
		let refreshId = req.body.userId + jwtSecret;
		let salt = crypto.randomBytes(16).toString('base64');
		let hash = crypto.createHmac('sha512', salt).update(refreshId).digest("base64");
		req.body.refreshKey = salt;
		let token = jwt.sign(req.body, jwtSecret);
		let b = Buffer.from(hash);
		let refresh_token = b.toString('base64');
		res.status(201).send({accessToken: token, refreshToken: refresh_token});
	} catch (err) {
		res.status(500).send({errors: err});
	}
};

雖然我們不會在此更新令牌,但控制器已被修復(fù)以方便這樣的時間,以便在接下來的開發(fā)中更簡單地執(zhí)行它。

我們現(xiàn)在需要的只是在 /authorization/routes.config.js 中創(chuàng)建路徑并調(diào)用適當(dāng)?shù)闹虚g件:

JavaScript:

app.post('/auth', [
	VerifyUserMiddleware.hasAuthValidFields,
	VerifyUserMiddleware.isPasswordAndUserMatch,
	AuthorizationController.login
]);

結(jié)果將在 accessToken 字段中包含創(chuàng)建的 JWT:e

JSON:

{
	"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1YjAyYzVjODQ4MTdiZjI4MDQ5ZTU4YTMiLCJlbWFpbCI6Im1hcmNvcy5oZW5yaXF1ZUB0b3B0YWwuY29tIiwicGVybWlzc2lvbkxldmVsIjoxLCJwcm92aWRlciI6ImVtYWlsIiwibmFtZSI6Ik1hcmNvIFNpbHZhIiwicmVmcmVzaF9rZXkiOiJiclhZUHFsbUlBcE1PakZIRG1FeENRPT0iLCJpYXQiOjE1MjY5MjMzMDl9.mmNg-i44VQlUEWP3YIAYXVO-74803v1mu-y9QPUQ5VY",
	"refreshToken": "U3BDQXBWS3kyaHNDaGJNanlJTlFkSXhLMmFHMzA2NzRsUy9Sd2J0YVNDTmUva0pIQ0NwbTJqOU5YZHgxeE12NXVlOUhnMzBWMGNyWmdOTUhSaTdyOGc9PQ=="
}

必須創(chuàng)建令牌,我們可以使用形式 Bearer ACCESS_TOKEN 在 Authorization 標(biāo)頭中使用它。

以上就是“Node.js中如何創(chuàng)建安全的REST API”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI