使用 JSON Web Token 保护你的 Node.js 应用程序
转载自CodeWall
当你构建一个前后端分离的 Web 应用程序时,一种将其置于登录状态的方法是使用JSONWebToken。这个概念在 2010 年代初推出后迅速流行起来。在本文中,你将了解什么是 JSON Web Token (JWT),它是如何工作的,以及如何将它集成到你的 Node.js 应用程序中。让我们开始吧!
JSON Web Token 简介
官网上写道:“JSON Web Token 是一种开放的、行业标准的方法,用于在双方之间安全地表达声明”。这意味着,服务器可以确定客户端发送的信息(JSON 格式)是否未被修改,并且是否由该服务器有效签发。
代币包含什么?
JSON Web Token 由三部分组成:
- 📃 Header:包含额外信息,例如令牌类型(JWT)以及所使用的签名算法(例如 SHA256)。标头 JSON 采用 Base64Url 编码。
- 📦 Payload:包含双方想要共享的信息(或“声明”)。这可以包含任何你想要的内容,但共享敏感数据(例如密码)永远不是一个好主意,因为默认情况下,JWT 令牌无需共享密钥即可解码。JWT 的目标不是加密数据。我个人通常使用用户 ID、角色、签发日期和到期日期。除了标头 JSON 之外,Payload JSON 也使用 Base64Url 编码。
- 🔏签名:签名包含编码的标头、编码的有效负载、秘密(只有您的服务器知道)并由标头中确定的算法签名。
如果散列算法是 SHA256,则签名将按如下方式创建:
HMACSHA256(
base64UrlEncode(header)
+ "."
+ base64UrlEncode(payload)
,secret)
最后,所有三个部分都被连接起来,用“。”分隔:
<Header>.<Payload>.<Signature>
下面是一个 JWT 示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZDM5YzI4MjdhZDgyMjBmMTJiMGZkMWIiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE1NjUyNzE4NzUsImV4cCI6MTU2NjQ4MTQ3NX0.NmcvfTBmUw1cdEI1cNRHzq6q5W0HmPELoh8rd_7EFAc
花点时间前往jwt.io并将令牌粘贴到那里。您将看到它包含的所有信息(签名除外)。
JWT 令牌如何工作?
需要注意的是,JWT 并非用于交换加密数据。它绝不能包含敏感信息,例如密码。JWT 的关键在于对令牌的验证。当您尝试验证已被篡改的令牌(例如用户 ID 被替换)时,该令牌将被拒绝。
为什么?因为内容不再与签名匹配。所以除了你之外的其他人无法创建有效的令牌,除非他们拿到了你用来哈希签名的密钥。
如果您的 JWT 密钥因某种原因被黑客入侵,您需要立即更改它。此后所有现有的令牌都将失效。这可能会让某些已登录的用户感到困扰,但您可以确保没有人能够为您的应用程序生成有效的令牌。
JWT 工作流程在服务器上是什么样的?
现在我们对 JWT 有了一定的了解,让我们看一个例子来了解它如何与客户端-服务器交换一起工作。
-
第一步是客户端。客户端可以是 Web 前端应用、移动应用等等。基本上,任何试图与后端应用交互的程序(例如 REST API)都可以。客户端会将用户的登录凭据发送到服务器进行验证。
-
当服务器收到登录请求时,它首先会确保用户名/邮箱地址和密码与数据库中存储的信息匹配。如果凭据正确,则意味着服务器确认该用户的身份。
-
接下来,生成 JWT 令牌。在这里,用于识别用户的重要信息被传递到有效负载中。最好也包含签发日期和到期日期。这样,会话的有效期永远不会超过您指定的时间。一周似乎是一个不错的时间跨度。无论如何,用户每次使用后都应该退出应用程序,对吧?但这只会增加额外的安全性,避免出现僵尸登录用户。
-
然后,令牌将作为登录尝试的响应返回给客户端。当客户端收到令牌时,这意味着登录成功。令牌应该存储在客户端本地的某个位置。对于 Web 应用程序,这可以是 localStore;对于移动应用程序,这可以是设备变量中的某个位置。
-
为了与服务器进行所有后续通信,客户端会在每个请求中添加一个身份验证标头。如下所示:
Authentication: Bearer -
当对受保护资源的新请求到达服务器时,服务器首先会检查请求中是否包含身份验证标头。如果包含,服务器会尝试验证令牌是否有效。如果令牌无效(例如已被篡改、已过期等),则应立即拒绝该请求。
-
但是,如果令牌有效,则服务器可以安全地假定用户仍然是他所说的那个人,并且可以将请求的资源作为响应返回给客户端。
Node.js 应用程序中的 JWT
在本文中,我不会详细介绍 Node.js 中的 Web 服务器工作原理。但我将向您展示如何在 JavaScript 服务器环境中使用 JWT。
准备
为了使用 JWT,你可以使用这个便捷的jsonwebtoken
库。安装方法如下:
npm install jsonwebtoken
创建令牌
在您确定客户端是否提供了正确的登录凭据的代码中(可能就在您检查数据库之后),您可以创建 JSON Web Token:
const token = jwt.sign(<Your payload>, <Your JWT secret>, { expiresIn: <Expiration Time> })
在真实的例子中,它可能看起来像这样:
const jwt = require('jsonwebtoken')
const token = jwt.sign({ _id: user._id, admin: true }, process.env.JWT_SECRET, { expiresIn: '1 week' })
请注意两件事:
- 如果您不熟悉
dotenv
,process.env.JWT_SECRET
则 JWT 密钥将存放于此。将令牌以明文形式存储在代码中绝不是一个好主意,因此最好使用诸如 dotenv [ https://www.npmjs.com/package/dotenv ] 之类的工具将其放置在不会上传到 Git 仓库的文件中。 - expiredIn 属性可以是字符串形式的人类可读的时间指示:-*'4 天'-*'7 小时'-*'2 周'-*'6 个月'-* 等。
验证令牌
您的客户端应将身份验证标头设置为: Bearer: 。因此,您首先需要"Bearer: "
从字符串中剥离该部分:
const token = req.header('Authorization').replace('Bearer ', '')
(req.header('Authorization') 是 Express.js 读取授权标头的方式)
然后,您可以按如下方式验证提供的令牌:
const jwt = require('jsonwebtoken')
try{
const payload = jwt.verify(token, process.env.JWT_SECRET)
console.log(payload._id)
} catch(error) {
console.error(error.message)
}
如果令牌有效,您将能够直接访问有效载荷变量中的所有有效载荷数据。如果令牌无效,JWT 库将抛出一个错误,您可以在 catch 中处理该错误。
概括
就是这样!如你所见,使用 JWT 并不复杂。最重要的一点——我再怎么强调也不为过——是 JWT 不会加密你的数据,因此请勿使用它来交换敏感信息。JSON
Web Token 是一项非常有效的技术,可以用来验证某人声称拥有的信息是否真实。
祝你编程愉快!