近年来,RESTful API 的使用越来越普遍,这种机制使得不同的系统之间可以相互交互,并实现数据的共享。但是,同时也带来了数据保密性和安全性的问题。为了解决这个问题,我们可以使用 JSON Web Tokens (JWTs) 和 Hapi.js 来保障 API 的安全性。
什么是 JSON Web Tokens (JWTs)
在深入了解 JWTs 之前,我们需要先了解一下什么是 token。在 Web 应用程序中,为了表示用户权限和识别用户数据,通常需要在用户登录后给出一个 token,然后把这个 token 附加到每个后来的请求中。在需要用户数据的地方,服务器可以根据这个 token 来验证用户的身份和权限。
JWTs 是另一种 token,但相比传统的 token,它们具有以下优点:
- 可以自包含所有的用户信息
- 可以签名、加密和解密
- 可以被用于安全的分布式系统认证
因此,除了在 web 应用程序中使用外,JWTs 在移动应用程序和 IoT 设备等地方也非常有用。
JSON Web Tokens(JWTs)是一种开放标准(RFC 7519),它定义了各个方面的声明在 JSON 格式中。这些信息可以被签名和/或加密后作为 token 传递,以确定其身份信息和所需访问的资源。
// JWT 示例 eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF 0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
使用 Hapi.js 和 JSON Web Tokens
下面我们将介绍如何使用 Hapi.js 和 JSON Web Tokens 来保护 API。
安装相关依赖
我们将使用 npm 包管理工具来安装必要的库。我们需要的依赖如下:
- hapi:Hapi 框架
- hapi-auth-jwt2:用于 JWT 身份验证
- jsonwebtoken:JWT 的生成实用程序
运行以下命令来安装上述依赖:
npm install --save hapi hapi-auth-jwt2 jsonwebtoken
实现 JWT 签名和验证
我们开始实现签名和验证 JWTs。首先创建一个名为 jwt.js
的文件来实现这个功能,代码实现如下:
// javascriptcn.com 代码示例 // 引入必要的依赖 const jwt = require('jsonwebtoken'); const secret = 'yourSecretKey'; // 这里要替换为自己的密钥 // 生成 JWTs exports.issueToken = (payload) => { const token = jwt.sign(payload, secret, { expiresIn: '1d' }); // 有效时长为 1 天 return token; }; // 验证 JWTs exports.verifyToken = (token) => { try { const decoded = jwt.verify(token, secret); return decoded; } catch (err) { return false; } };
如上代码,我们首先引入了必要的库,然后定义了一个密钥(即 secret
)。在 issueToken
方法中,我们使用 jwt 包的 sign()
方法来生成基于输入数据(即 payload
)和密钥的 JWT。在这里,我们还为 JWT 指定了一个有效时间(expiresIn
)。否则,JWTs 将永远有效。
另一方面,在 verifyToken
方法中,我们使用 jwt 包的 verify()
方法来验证传入的 JWT。如果 JWT 有效,将返回解码的数据,否则将返回 false
。
创建一个 Hapi.js 服务器
下一步是创建一个 Hapi.js 服务器,并实现 JWT 的身份验证。下面是基本的启动文件 index.js
:
// javascriptcn.com 代码示例 // 引入必要的依赖 const Hapi = require('hapi'); const jwt = require('./jwt'); // 上述实现 JWT 签名和验证的文件 // 创建 Hapi.js 服务器 const server = new Hapi.Server({ port: process.env.PORT || 3000, routes: { cors: { origin: ['*'], // 跨域设置 - 允许任何来源 credentials: true } } }); // 定义基于 JWTs 的身份验证 const validate = async (decoded, request, h) => { if (decoded) { // 这里可以添加其他自定义验证逻辑 return { isValid: true }; } return { isValid: false }; }; // 注册 JWT 插件 const init = async () => { await server.register(require('hapi-auth-jwt2')); server.auth.strategy('jwt', 'jwt', { key: 'yourSecretKey', // 这里要替换为自己的密钥 validate, verifyOptions: { algorithms: ['HS256'] }, }); server.auth.default('jwt'); }; init(); // 定义路由 server.route({ method: 'GET', path: '/', handler: (request, h) => { return 'hello world!'; }, config: { auth: false } }); server.route({ method: 'GET', path: '/protected', handler: (request, h) => { return 'JWT protected'; }, config: { auth: 'jwt' } }); // 启动服务器 (async () => { await server.start(); console.log(`Server running at: ${server.info.uri}`); })();
如上代码,我们首先引入了必要的包和刚刚我们写的 JWT 签名和验证模块。然后我们创建了一个 Hapi.js 服务器,并通过调用 server.register()
方法来注册 hapi-auth-jwt2
插件。
下一步我们实现基于 JWT 的身份验证方式。使用 server.auth.strategy()
方法来定义我们的验证策略。在这里我们指定了密钥(yourSecretKey
)和解码验证选项(verifyOptions
)。我们还实现了一个 validate
方法来验证解码后的 JWT 是否有效。
最后,我们定义了两个路由,第一个不需要 JWT 验证,而第二个需要进行验证。如果 JWTs 验证通过,则返回 JWT protected
,否则返回 401 Unauthorized
。
测试
运行 node index.js
命令来启动本地服务器,访问 http://localhost:3000/
能够返回 hello world!
,而访问 http://localhost:3000/protected
则会返回 401 Unauthorized
。
下面我们通过 Postman 工具来测试有身份验证的 API:
- 先打开 Postman,然后在 Headers 中添加
Content-Type: application/json
和Authorization: Bearer <token>
。其中<token>
是我们使用生成 JWT 的签名代码生成的 token。 - 然后在 Postman 上点击 “Send” 按钮,我们就能够成功的访问到受到保护的 API 接口。
这里我们提供一个生成 JWT 的样例代码供参考:
const token = jwt.issueToken({ username: 'sang', role: 'admin' });
这将返回一个 JWT,可以将其附加到后续的请求中(作为 Authorization
头的值)来进行验证。
总结
JSON Web Tokens 具有自包含、可签名和可加密的优点,使其在分布式系统中的身份验证非常有用。本文介绍了如何使用 Hapi.js 和 JSON Web Tokens 实现基于 JWT 的身份验证。我们通过刚刚提到的 jwt.js
文件模块和测试用例,详细说明了如何签名和验证 JWT,同时也提供了一个完整示例代码供大家参考。在实际开发中,需要根据实际情况进行修改,比如密钥长度、过期时间等。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653f3da07d4982a6eb8c528b