在现代 Web 应用程序中,认证和授权是不可避免的话题。Koa2 是一款流行的 Node.js Web 框架,并且可以非常方便地实现认证和授权功能。本文将详细介绍如何使用 Koa2 构建一个带有认证和授权的 Web 应用程序,并提供示例代码来指导读者实践。
准备工作
在开始之前,确保你已经安装了 Node.js 和 npm。如果没有,请到 Node.js 官网下载并安装。
在一个新的目录中创建一个空的项目:
mkdir koa-auth cd koa-auth npm init -y
接下来,安装需要的依赖:
npm install koa koa-router koa-bodyparser jsonwebtoken bcryptjs npm install --save-dev nodemon
以上命令安装了 Koa2、Koa2 路由、Koa2 bodyparser、JSON Web Token、bcryptjs(用于密码哈希)和 nodemon(用于自动重启服务器)。
编写代码
应用程序结构
接下来我们来设置应用程序的基本结构,项目结构如下。
-- -------------------- ---- ------- -------- --- ------------ --- --- - --- ----------- - --- -- - --- ------ - --- ------ - --- ----- --- ------------ --- ------
其中:
- controllers:存放路由逻辑代码
- db:存放数据库连接和操作代码
- models:存放数据模型定义代码
- routes:存放路由定义代码
- utils:存放工具函数代码
- app.js:应用程序入口文件
数据库设置
首先,让我们来连接到 MongoDB 数据库。在 src/db/index.js
中添加以下代码:
-- -------------------- ---- ------- ----- -------- - -------------------- ----- --------- - ----- -- -- - --- - ----- ---- - ----- --------------------------------------- - ---------------- ----- --------------- ----- ------------------- ----- --- -------------------- ---------- -------------------------- - ----- ----- - --------------------- ----------------- ---------------- - -- -------------- - ----------
这段代码中,我们使用 Mongoose 连接到 MongoDB 数据库,并且输出连接的结果。接下来,在应用程序的入口文件 app.js
中使用以上代码来连接数据库:
-- -------------------- ---- ------- --------------------------- ----- --- - --------------- ----- ---------- - -------------------------- ----- --------- - -------------------- ----- --- - --- ------ -- ----- ---------------------- -- ------ ------------ ---------------------------- -- -- ------------------- --------- -- ---- ------------------------ --
在 app.js
中,我们调用 connectDB()
函数来连接到数据库,同时也配置了请求体解析中间件和启动服务器。
用户模型
我们需要一个用户模型来存储用户的用户名和密码。在 src/models/User.js
中添加以下代码:
-- -------------------- ---- ------- ----- -------- - -------------------- ----- ------ - -------------------- ----- ---------- - --- ----------------- --------- - ----- ------- --------- ----- ------- ----- -- --------- - ----- ------- --------- ----- -- --- -- -------------- ---------------------- ----- -------- ------ - -- ------------------------------ - ------ ------- - ----- ---- - ----- ------------------- ------------- - ----- -------------------------- ------ ------- --- -- ------------- -------------------------------- - ----- -------- ---------- - ------ ----- ------------------------ --------------- -- -------------- - ---------------------- ------------
在以上代码中,我们定义了一个用户模型,模型有两个属性:username
和 password
。为了保护用户的密码,我们使用 bcryptjs
库来对密码进行哈希。在保存用户之前,我们使用 pre
钩子来对密码进行哈希;在校验用户输入的密码时,我们使用 checkPassword
方法来校验密码是否正确。
用户路由
接下来,我们来定义用户路由。在 src/routes/user.js
中添加以下代码:
-- -------------------- ---- ------- ----- ------ - ---------------------- ----- --- - ------------------------ ----- ---- - -------------------------- ----- - --------------- - - ------------------------- ----- ------ - --- -------- ------- ----------- --- -- ---- ------------------------ ----- ----- -- - ----- - --------- -------- - - ----------------- -- ---------- -- ---------- - -------------- -------------- - ----- ---- - --- ------ --------- -------- --- --- - ----- ------------ -------- - - -------- ------ -- - ----- ----- - -------------- ------------- - --- -- ---- --------------------- ----- ----- -- - ----- - --------- -------- - - ----------------- ----- ---- - ----- -------------- -------- --- -- ------ -- ------- ------------------------------ - -------------- ------------- - ----- ----- - ---------- -------- -- ------------------------ -------- - - ----- -- --- -- -------- ----------------- ----- ----- -- - ----- ----------- - ---------------------------------- ----- ----- - ----------------------------- ----- ---- - ----- -------------- --------- -------------- --- -- ------- - -------------- --------- - -------- - - --------- ------------- -- --- -------------- - -------
在用户路由中,我们定义了三个接口:
/api/user/register
:注册用户接口,接受用户名和密码,将用户保存到数据库中/api/user/login
:用户登录接口,接受用户名和密码,检查用户名和密码是否正确,并且返回一个 JSON Web Token/api/user/me
:获取当前登录用户的接口,需要用户传递 JSON Web Token,通过解析 Token 来获取当前登录的用户
在以上代码中,我们使用了 jsonwebtoken
库来进行 Token 签名和解析,使用了 getUserFromToken
函数来解析 Token,从而获取解码后的用户名。此外,还使用了 ctx.throw()
函数来抛出错误,用于统一错误处理。
应用入口
在应用程序入口文件 app.js
中,我们导入并使用路由,如下所示:
-- -------------------- ---- ------- --------------------------- ----- --- - --------------- ----- ---------- - -------------------------- ----- ---- - --------------------- ----- --------- - -------------------- ----- ---------- - ----------------------------- ----- --- - --- ------ -- ----- ---------------------- -- ---- ---------------- -- ------ ------------ -- ---- ----------------------------- ---------------------------- -- -- ------------------- --------- -- ---- ------------------------ --
在 app.js
中,我们同时使用了 koa-cors
库来实现跨域处理,以便于能够使用不同的域名或端口来访问本地 Web 服务。
鉴权中间件
我们需要编写一个授权验证的中间件,以确保只有登录的用户才能访问资源。在 src/utils/auth.js
中添加以下代码:
-- -------------------- ---- ------- ----- --- - ------------------------ ----- --------------- - ------------- -- - ----- -- ------ - ------------------- --- ------ ----------------- ------------------------ -- ----- ---- - ----- ----- ----- -- - ----- ----------- - ---------------------------------- -- -------------- - -------------- ------ ----- - --- - ----- ----- - ----------------------------- -------------- - --------------- - ----- ----- - -------------- ------ ------ - ----- ------- -- -------------- - - ----- --------------- --
在以上代码中,我们使用 getTokenPayload
函数来解析 Token,并且将解密后的用户名写入 Koa 的状态中。这使得在其他中间件中,我们可以轻松地访问到解密后的用户名。
保护资源路由
最后,我们需要编写一个受保护的路由来展示如何使用鉴权中间件。在 src/routes/protection.js
中添加以下代码:
-- -------------------- ---- ------- ----- ------ - ---------------------- ----- - ---- - - ------------------------- ----- ------ - --- -------- ------- ----------------- --- --------------- ----- ----- ----- -- - -------- - - -------- --------------- -- --- -------------- - -------
在资源路由中,我们只需要使用 auth
中间件来确保用户已经登录,并且可以直接读取 Koa 的状态中存储的当前登录用户名,从而进行更复杂的鉴权操作。
总结
在本文中,我们详细介绍了如何使用 Koa2 构建一个带有认证和授权的 Web 应用程序。我们展示了如何使用 MongoDB 来存储用户信息、如何生成和解码 JSON Web Token、如何编写鉴权中间件以及如何保护一些受保护的资源。我们相信本文对于初学者具有较强的指导意义,并且提供了一些非常有价值的示例代码供读者参考和学习。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65863ee3d2f5e1655d0a083a