web api json
What a mouthful of a title. Wouldn’t you agree? In this walkthrough you’ll learn about securing your Serverless endpoints with JSON web tokens.
这么大的头衔。 你不同意吗? 在本演练中,您将学习如何使用JSON Web令牌保护无服务器端点。
This will include a basic setup of a Serverless REST API with a few endpoints, and of course an authorizer function. This authorizer will act as the middleware for authorizing access to your resources.
这将包括具有几个端点的无服务器REST API的基本设置,当然还有授权者功能。 该授权者将充当授权访问您的资源的中间件。
During the creation process, we’ll use the Serverless framework for simulating a development environment just like you’re used to. Wrapping up the guide we’ll also set up a monitoring tool called Dashbird. It will allow us to simulate the debugging capabilities and overview of a regular Node.js application in a way that’s natural and easy to comprehend. It also has a free tier and doesn’t require a credit card to set up.
在创建过程中,我们将像您一样使用Serverless框架来模拟开发环境。 在编写指南的同时,我们还将建立一个名为Dashbird的监视工具。 这将使我们能够以自然且易于理解的方式模拟调试功能和常规Node.js应用程序的概述。 它还有一个免费套餐,不需要信用卡即可设置。
If anything I just mentioned above is new to you, don’t worry. I’ll explain it all below. Otherwise you can freshen up your knowledge by taking a look at these tutorials:
如果我上面刚刚提到的任何东西对您来说都不新鲜,请不要担心。 我将在下面解释所有内容。 否则,您可以通过阅读以下教程来增强知识:
Securing Node.js RESTful APIs with JWT — Authentication and Authorization explained.
使用JWT保护Node.js RESTful API的安全 -解释了身份验证和授权。
A crash course on Serverless with Node.js— Serverless basics explained.
使用Node.js的 Serverless 速成课程 —解释了Serverless的基础知识。
Building a Serverless REST API with Node.js and MongoDB — Serverless REST APIs explained.
使用Node.js和MongoDB构建无服务器REST API —说明了无服务器REST API。
TL; DR (TL;DR)
Before jumping in head first, you can severely hurt my feelings and only read this TL;DR. Or, continue reading the whole article. ❤
在先跳头之前,您可能会严重伤害我的感情,仅阅读此TL; DR。 或者,继续阅读全文。 ❤
-
-
--
-
--
-
--
Adding business logic for the users
-
--
-
--
Ready? Let’s jump in!
准备? 让我们跳进去!
创建API (Creating the API)
First of all, we need to set up the Serverless framework for our local development environment. This framework is the de facto framework for all things related to Serverless architectures. Jump over to their site and follow the instructions to set it up, or reference back to the article I linked above.
首先,我们需要为本地开发环境设置无服务器框架。 该框架是与无服务器架构有关的所有事物的事实上的框架。 跳转到他们的网站并按照说明进行设置,或者参考上面我链接的文章 。
The installation process is incredibly simple. You set up an AWS management role in your AWS account, and link it to your installation of the Serverless framework. The actual installation process is just running one simple command.
安装过程非常简单。 您在您的AWS账户中设置了一个AWS管理角色,并将其链接到您的无服务器框架的安装。 实际的安装过程只是运行一个简单的命令。
Fire up a terminal window and run the command below.
启动终端窗口并运行以下命令。
$ npm install -g serverless
Moving on, once you have it installed, there’s only one more command to run in the terminal to get a boilerplate Serverless service on your local development machine.
继续,一旦安装完毕,在终端中只需要再运行一个命令即可在本地开发计算机上获得样板的无服务器服务。
$ sls create -t aws-nodejs -p api-with-auth
The command above will generate the boilerplate code you need.
上面的命令将生成您所需的样板代码。
Change to the newly created directory called api-with-auth
and open it up with your code editor of choice.
转到新创建的名为api-with-auth
目录,然后使用您选择的代码编辑器将其打开。
$ cd api-with-auth
Once open, you’ll see two main files. A handler.js
and a serverless.yml
file. The handler.js
contains our app logic while the serverless.yml
defines our resources.
打开后,您将看到两个主要文件。 一个handler.js
和一个serverless.yml
文件。 handler.js
包含我们的应用程序逻辑,而serverless.yml
定义了我们的资源。
Now it’s time to install some dependencies in order to set up our needed authentication/authorization methods, password encryption and ORM for the database interaction.
现在该安装一些依赖项,以设置我们所需的身份验证/授权方法,密码加密和数据库交互的ORM。
$ npm init -y$ npm install --save bcryptjs bcryptjs-then jsonwebtoken mongoose
There’s what we need for production, but for development we’ll grab the Serverless Offline plugin.
这是生产所需的,但是对于开发,我们将获取Serverless Offline插件。
$ npm install --save-dev serverless-offline
Lovely!
可爱!
添加数据库 (Adding a database)
For the persistent data store, we’ll just grab a hosted MongoDB instance on MongoDB Atlas. Here’s a reference for an article where I explained it in detail.
对于持久性数据存储,我们只需在MongoDB Atlas上获取托管的MongoDB实例。 这是我详细解释文章的参考。
In the root of the service folder let’s create a db.js
file to keep our logic for the database connection. Go ahead and paste in this snippet of code.
在服务文件夹的根目录中,我们创建一个db.js
文件来保留数据库连接的逻辑。 继续并粘贴此代码段。
This is a rather simple implementation of establishing a database connection if no connection exists. But, if it exists, I’ll use the already established connection. You see the process.env.DB
? We'll use a custom secrets.json
file to keep our private keys out of GitHub by adding it to the .gitignore
. This file will then be loaded in the serverless.yml
. Actually, let's do that now.
如果不存在连接,这是建立数据库连接的相当简单的实现。 但是,如果存在,我将使用已经建立的连接。 您看到了process.env.DB
吗? 我们将使用自定义的secrets.json
文件,通过将其添加到.gitignore
来将私钥保留在GitHub之外。 然后,该文件将被加载到serverless.yml
。 实际上,让我们现在开始。
Add your MongoDB connection string to the db
field.
将您的MongoDB连接字符串添加到db
字段。
With this file created, let’s move on to the serverless.yml
. Open it up and delete all the boilerplate code so we can start fresh. Then, go ahead and paste this in.
创建此文件后,让我们继续到serverless.yml
。 打开它并删除所有样板代码,以便我们重新开始。 然后,继续粘贴。
As you can see, it’s just a simple setup configuration. The custom
section tells the main configuration to grab values from a secrets.json
file. We'll add that file to the .gitignore
because pushing private keys to GitHub is a mortal sin punishable by death! Not really, but still, don't push keys to GitHub. Seriously, please don't.
如您所见,这只是一个简单的设置配置。 custom
部分告诉主配置从secrets.json
文件中获取值。 我们将该文件添加到.gitignore
因为将私钥推送到GitHub是一种致命罪,应处以死刑! 并非如此,但仍然不要将键推到GitHub。 说真的,请不要。
添加功能 (Adding the functions)
Just a tiny bit of configuring left to do before jumping into the business logic! We need to add the function definitions in the serverless.yml
right below the providers section we added above.
在跳入业务逻辑之前,只需要进行一点点配置即可! 我们需要在上面添加的providers部分下面的serverless.yml
添加函数定义。
There are a total of five functions.
一共有五个功能。
The
VerifyToken.js
will contain an.auth
method for checking the validity of the JWT passed along with the request to the server. This will be our authorizer function. The concept of how an authorizer works is much like how a middleware works in plain old basic Express.js. Just a step between the server receiving the request and handling data to be sent back to the client.VerifyToken.js
将包含一个.auth
方法,用于检查与请求一起传递给服务器的JWT的有效性。 这将是我们的授权者功能。 授权者的工作原理很像中间件在普通的基本Express.js中的工作方式。 在服务器接收请求和处理要发送回客户端的数据之间的一个步骤。The
login
andregister
functions will do the basic user authentication. We'll add business logic for those in theAuthHandler.js
file.login
和register
功能将执行基本的用户身份验证。 我们将在AuthHandler.js
文件中添加业务逻辑。However, the
me
function will respond with the current authenticated user based on the provided JWT token. Here's where we'll use the authorizer function.但是,
me
函数将基于提供的JWT令牌与当前经过身份验证的用户进行响应。 这是我们使用授权者功能的地方。The
getUsers
function is just a generic public API for fetching registered users from the database.getUsers
函数只是用于从数据库中获取注册用户的通用公共API。
From the serverless.yml
file above you can make out a rough project structure. To make it clearer, take a look at the image above.
从上面的serverless.yml
文件中,您可以得出一个大致的项目结构。 为了更加清晰,请看上图。
Makes a bit more sense now? Moving on, let’s add the logic for fetching users.
现在更有意义了吗? 继续,让我们添加获取用户的逻辑。
为用户添加业务逻辑 (Adding business logic for the users)
Back in your code editor, delete the handler.js
file and create a new folder, naming it user
. Here you'll add a User.js
file for the model, and a UserHandler.js
for the actual logic.
返回代码编辑器,删除handler.js
文件并创建一个新文件夹,将其命名为user
。 在这里,您将添加一个User.js
文件的模型和UserHandler.js
的实际逻辑。
Pretty straightforward if you’ve written a Node app before. We require Mongoose, create the schema, add it to Mongoose as a model, finally exporting it for use in the rest of the app.
如果您之前编写过Node应用程序,则非常简单。 我们需要Mongoose,创建架构,将其作为模型添加到Mongoose,最后将其导出以在应用程序的其余部分中使用。
Once the model is done, it’s time to add basic logic.
模型完成后,就该添加基本逻辑了。
This is a bit tricky to figure out when you see it for the first time. But let’s start from the top.
第一次看到时很难弄清楚。 但是,让我们从头开始。
By requiring the db.js
we have access to the database connection on MongoDB Atlas. With our custom logic for checking the connection, we've made sure not to create a new connection once one has been established.
通过要求db.js
我们可以访问MongoDB Atlas上的数据库连接。 利用我们用于检查连接的自定义逻辑,我们确保一旦建立了连接就不会创建新连接。
The getUsers
helper function will only fetch all the users, while the module.exports.getUsers
Lambda function will connect to the database, run the helper function, and return the response back to the client. This is more than enough for the UserHandler.js
. The real fun starts with the AuthProvider.js
.
getUsers
帮助器函数将仅获取所有用户,而module.exports.getUsers
Lambda函数将连接到数据库,运行帮助器函数,并将响应返回给客户端。 对于UserHandler.js
,这UserHandler.js
。 真正的乐趣始于AuthProvider.js
。
添加身份验证 (Adding the authentication)
In the root of your service, create a new folder called auth
. Add a new file called AuthHandler.js
. This handler will contain the core authentication logic for our API. Without wasting any more time, go ahead and paste this snippet into the file. This logic will enable user registration, saving the user to the database and returning a JWT token to the client for storing in future requests.
在服务的根目录中,创建一个名为auth
的新文件夹。 添加一个名为AuthHandler.js
的新文件。 该处理程序将包含我们API的核心身份验证逻辑。 不要浪费更多的时间,继续并将此代码段粘贴到文件中。 该逻辑将启用用户注册,将用户保存到数据库中,并将JWT令牌返回给客户端以存储在将来的请求中。
First we require the dependencies, and add the module.exports.register
function. It's pretty straightforward. We're once again connecting to the database, registering the user and sending back a session object which will contain a JWT token. Take a closer look at the local register()
function, because we haven't declared it yet. Bare with me a few more seconds, we’ll get to it in a moment.
首先,我们需要依赖项,并添加module.exports.register
函数。 这很简单。 我们再次连接到数据库,注册用户并发送回包含JWT令牌的会话对象。 请仔细查看本地register()
函数,因为我们尚未对其进行声明。 再等我几秒钟,我们待会儿处理。
With the core structure set up properly, let’s begin with adding the helpers. In the same AuthHandler.js
file go ahead and paste this in as well.
在正确设置核心结构之后,让我们开始添加助手。 在同一AuthHandler.js
文件中,继续并将其粘贴。
We’ve created three helper functions for signing a JWT token, validating user input, and creating a user if they do not already exist in our database. Lovely!
我们创建了三个帮助器函数,用于对JWT令牌进行签名,验证用户输入以及在数据库中尚不存在的情况下创建用户。 可爱!
With the register()
function completed, we still have to add the login()
. Add the module.exports.login
just below the functions comment.
完成register()
函数后,我们仍然必须添加login()
。 在功能注释下方添加module.exports.login
。
Once again we have a local function, this time named login()
. Let's add that as well under the helpers comment.
再一次,我们有一个本地函数,这次命名为login()
。 我们还要在助手注释下添加它。
Awesome! We’ve added the helpers as well. With that, we’ve added authentication to our API. As easy as that. Now we have a token-based authentication model with the possibility of adding authorization. That’ll be our next step. Hang on!
太棒了! 我们也添加了助手。 这样,我们就向API添加了身份验证 。 就这么简单。 现在,我们有了一个基于令牌的身份验证模型,可以添加授权。 那将是我们的下一步。 不挂断!
添加授权 (Adding the authorization)
With the addition of a VerifyToken.js
file, we can house all the authorization logic as a separate middleware. Very handy if we want to keep separation of concerns. Go ahead and create a new file called VerifyToken.js
in the auth
folder.
通过添加VerifyToken.js
文件,我们可以将所有授权逻辑作为单独的中间件存放。 如果我们要保持关注点分离,非常方便。 继续,在auth
文件夹中创建一个名为VerifyToken.js
的新文件。
We have a single function exported out of the file, called module.exporst.auth
with the usual three parameters. This function will act as a middleware. If you're familiar with Node.js you'll know what a middleware is, otherwise, check this out for a more detailed explanation.
我们从文件中导出了一个函数,称为module.exporst.auth
具有通常的三个参数。 此功能将充当中间件 。 如果你熟悉Node.js的,你就会知道中间件是什么,否则,检查这出了更详细的解释。
The authorizationToken
, our JWT, will be passed to the middleware through the event. We're just assigning it to a local constant for easier access.
我们的JWT的authorizationToken
将通过该事件传递给中间件。 我们只是将其分配给本地常量,以便于访问。
All the logic here is just to check whether the token is valid and send back a generated policy by calling the generatePolicy
function. This function is required by AWS, and you can grab it from various docs on AWS and from the Serverless Framework examples GitHub page.
这里的所有逻辑只是检查令牌是否有效,并通过调用generatePolicy
函数将生成的策略发送回去。 AWS要求此功能,您可以从AWS上的各种文档以及无服务器框架示例GitHub页面中获取 。
It’s important because we pass along the decoded.id
along in the callback
. Meaning, the next Lambda Function which sits behind our VerifyToken.auth
authorizer function will have access to the decoded.id
in its event
parameter. Awesome, right!?
这很重要,因为我们在callback
传递了decoded.id
。 意思是,位于我们的VerifyToken.auth
授权者函数后面的下一个Lambda函数将可以访问其event
参数中的decoded.id
。 太好了,对!!
Once we have the token verification completed, all that’s left if to add a route to sit behind the authorizer function. For the sake of simplicity, let’s add a /me
route to grab the currently logged user based on the JWT passed along the GET
request.
一旦我们完成了令牌验证,剩下的就是添加一条添加到授权者函数后面的路由。 为了简单起见,让我们添加一个/me
路由,以基于GET
请求传递的JWT来捕获当前登录的用户。
Jump back to the AuthHandler.js
file and paste this in.
跳回到AuthHandler.js
文件并将其粘贴。
Awesome! The last Lambda Function we’ll add in this tutorial will be module.exports.me
. It'll just grab the userId
passed from the authorizer and call the me
helper function while passing in the userId
. The me
function will grab the user from the database and return it back. All the module.exports.me
Lambda does is just retrieves the currently authenticated user. But, the endpoint is protected, meaning only a valid token can access it.
太棒了! 我们将在本教程中添加的最后一个Lambda函数将是module.exports.me
。 它只会抓住userId
从授权通过,并调用me
助手功能,同时通过在userId
。 me
函数将从数据库中抓取用户并将其返回。 Lambda所做的所有module.exports.me
只是检索当前经过身份验证的用户。 但是,端点是受保护的,这意味着只有有效的令牌才能访问它。
Great work following along so far, let’s deploy it so we can do some testing.
到目前为止,我们将继续进行出色的工作,让我们进行部署,以便进行一些测试。
部署方式 (Deployment)
Hopefully, you’ve configured your AWS account to work with the Serverless Framework. If you have, there’s only one command to run, and you’re set.
希望您已将您的AWS账户配置为可与无服务器框架一起使用。 如果有的话,只有一个命令可以运行,并且已经设置好。
$ sls deploy
Voila! Wait for it to deploy, and start enjoying your Serverless API with JWT authentication and authorization.
瞧! 等待它部署,然后开始使用带有JWT身份验证和授权的无服务器API。
You’ll get a set of endpoints sent back to you in the terminal once the functions have been deployed. We’ll be needing those in the next section.
部署功能后,您将在终端中收到一组端点发送回给您。 在下一节中,我们将需要这些。
测试中 (Testing)
The last step in any development process should ideally be making sure it all works like it should. This is no exception. One of the two tools I use for testing my endpoints is Insomnia. So, I’ll go ahead and open it up. But, you can use Postman, or any other tool you like.
理想情况下,任何开发过程的最后一步都应该确保所有工作都按预期进行。 也不例外。 我用于测试端点的两个工具之一是Insomnia 。 因此,我将继续打开它。 但是,您可以使用Postman或任何您喜欢的其他工具。
Note: If you want to start by testing everything locally, be my guest. You can always use serverless-offline.
注意 :如果您想从本地进行所有测试,请成为我的客人。 您始终可以使用serverless-offline 。
In your terminal, run a simple command:
在您的终端中,运行一个简单的命令:
$ sls offline start --skipCacheInvalidation
But I like to go hardcore! Let’s test directly on the deployed endpoints.
但是我喜欢成为铁杆! 让我们直接在部署的端点上进行测试。
Starting slow, first hit the /register
endpoint with a POST
request. Make sure to send the payload as JSON. Hit Send and you'll get a token back! Nice, just what we wanted.
起步缓慢,首先使用POST
请求命中/register
端点。 确保将有效负载作为JSON发送。 点击发送 ,您将获得令牌! 很好,正是我们想要的。
Copy the token and now hit the /me
endpoint with a GET
request. Don't forget to add the token in the headers with the Authorization
key.
复制令牌,然后使用GET
请求访问/me
端点。 不要忘记使用Authorization
密钥在标头中添加令牌。
You’ll get the current user sent back to you. And there it is. Lovely.
您会把当前用户发回给您。 在那里。 可爱。
Just to make sure the other endpoints work as well, go ahead and hit the /login
endpoint with the same credentials as with the /register
endpoint you hit just recently.
为了确保其他端点也正常工作,请继续使用与最近/login
的/register
端点相同的凭据来命中/login
端点。
Does it work? Of course it does. There we have it, a fully functional authentication and authorization system implemented in a Serverless environment with JWT and Authorizers. All that’s left is to add a way to monitor everything.
它行得通吗? 当然可以。 我们拥有一个在JWT和Authorizers的无服务器环境中实现的功能齐全的身份验证和授权系统。 剩下的就是添加一种监视所有内容的方法。
监控方式 (Monitoring)
I usually monitor my Lambdas with Dashbird. It’s been working great for me so far. My point for showing you this is for you too see the console logs from the Lambda Function invocations. They’ll show you when the Lambda is using a new or existing database connection. Here’s what the main dashboard looks like, where I see all my Lambdas and their stats.
我通常使用Dashbird监视Lambda。 到目前为止,对我来说一直很好。 向我展示这一点是因为您也可以从Lambda函数调用中看到控制台日志。 当Lambda使用新的或现有的数据库连接时,它们将向您显示。 这是主仪表板的外观,在这里我可以查看所有Lambda及其统计信息。
Pressing on one of the Lambda Functions, let’s say register, you’ll see the logs for that particular function. The bottom will show a list of invocations for the function. You can even see which were crashes and cold starts.
按下Lambda函数之一,即注册 ,您将看到该特定函数的日志。 底部将显示该函数的调用列表。 您甚至可以查看哪些是崩溃和冷启动。
Pressing on the cold start invocation will take you to the invocation page and you’ll see a nice log which says => using new database connect
ion.
按下冷启动调用将带您进入调用页面,您将看到一个漂亮的日志,其中显示=> using new database connect
。
Now backtrack a bit, and pick one of the invocations which is not a cold start. Checking the logs for this invocation will show you => using existing database connect
ion.
现在回溯一下,然后选择一个调用,这不是一个冷门。 检查此调用的日志将显示=> using existing database connect
。
Nice! You have proper insight into your system!
真好! 您对系统有适当的了解!
结语 (Wrapping up)
Amazing what you can do with a few nice tools. Creating a REST API with authentication and authorization is made simple with Serverless, JWT, MongoDB, and Dashbird. Much of the approach to this tutorial was inspired by some of my previous tutorials. Feel free to check them out below.
使用一些不错的工具,您可以做什么。 使用Serverless ,JWT,MongoDB和Dashbird可以轻松创建具有身份验证和授权的REST API。 本教程的许多方法都受到我以前的一些教程的启发。 请随时在下面查看它们。
Adnan Rahić - MediumRead writing from Adnan Rahić on Medium. Co-founder @bookvar_co. Teacher @ACADEMY387. Author @PacktPub. Campsite leader…medium.com
AdnanRahić-中 阅读AdnanRahić在Medium上的写作。 联合创始人@bookvar_co。 老师@ ACADEMY387。 作者@PacktPub。 营地负责人… medium.com
The approach of using authorizers to simulate middleware functions is incredibly powerful for securing your Serverless APIs. It’s a technique I use on a daily basis. Hopefully you’ll find it of use in your future endeavors as well!
使用授权者来模拟中间件功能的方法对于保护无服务器API的功能非常强大。 我每天都使用这项技术。 希望您在以后的工作中也会发现它的用处!
If you want to take a look at all the code we wrote above, here’s the repository. Or if you want to dig deeper into the lovely world of Serverless, have a look at all the tools I mentioned above, or check out a course I authored.
如果您想看一下我们上面编写的所有代码, 这里是存储库 。 或者,如果您想深入研究Serverless的美好世界,请查看我上面提到的所有工具,或者查看我编写的课程 。
Hope you guys and girls enjoyed reading this as much as I enjoyed writing it. Do you think this tutorial will be of help to someone? Do not hesitate to share. If you liked it, smash the clap below so other people will see this here on Medium.
希望你们和我喜欢写这本书一样喜欢阅读。 您认为本教程对某人有帮助吗? 不要犹豫,分享。 如果您喜欢它,请粉碎 下面 的 拍手 ,以便其他人可以在Medium上看到。
web api json