JSON Web令牌(JWT)解释

了解JWT的基础知识以及如何使用它们

JSON Web令牌是用于为应用程序创建访问令牌的标准。

它是这样工作的:服务器生成一个证明用户身份的令牌,并将其发送给客户端。

客户端将针对每个后续请求将令牌发送回服务器,因此服务器知道请求来自特定身份。

这种体系结构在现代Web应用程序中被证明是非常有效的,在现代Web应用程序中,在对用户进行身份验证之后,我们将向REST或GraphQL API执行API请求。

谁使用JWT?以Google为例。如果您使用Google API,则将使用JWT。

JWT是经过密码签名的(但不是加密,因此在将用户数据存储在JWT中时必须使用HTTPS),因此可以保证我们在接收到它时就可以信任它,因为没有中间人可以拦截和修改它或它保存的数据而不会使其无效。

也就是说,JWT经常因使用过多而受到批评,尤其是当可以使用问题较少的解决方案时使用它们。

您需要围绕该主题形成您的意见。我并不是在提倡一项技术,而是要提供所有可用的机会和工具。

它们有什么用?主要是API身份验证和服务器到服务器授权。

JWT令牌是如何生成的?

使用Node.js,可以使用以下代码生成令牌的第一部分:

const header = { "alg": "HS256", "typ": "JWT" }
const encodedHeader = Buffer.from(JSON.stringify(header)).toString('base64')

我们将签名算法设置为HMAC SHA256(JWT支持多种算法),然后我们从此JSON编码对象创建一个缓冲区,然后使用base64对其进行编码。

部分结果是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

接下来,我们添加有效载荷,我们可以使用任何类型的数据对其进行自定义。有保留键,包括issexp标识发行者和令牌的到期时间。

您可以使用对象将自己的数据添加到令牌中:

const payload = { username: 'Flavio' }

我们将这个经过JSON编码的对象转换为Buffer,并使用base64对结果进行编码,就像我们之前所做的那样:

const encodedPayload = Buffer.from(JSON.stringify(payload)).toString('base64')

在这种情况下,部分结果是eyJ1c2VybmFtZSI6IkZsYXZpbyJ9

接下来,我们从标头和有效内容中获取签名,以确保即使被截取也不会更改我们的内容,因为签名将无效。为此,我们将使用crypto节点模块

const crypto = require('crypto')
const jwtSecret = 'secretKey'

const signature = crypto.createHmac(‘sha256’, jwtSecret).update(encodedHeader + ‘.’ + encodedPayload).digest(‘base64’)

我们使用secretKey密钥并创建加密签名的base64编码表示。

在我们的案例中,签名的价值是

MQWECYWUT7bayj8miVgsj8KdYI3ZRVS+WRRZjfZrGrw=

我们差不多完成了,我们只需要通过用点分隔它们来将标头,有效负载和签名的3个部分连接起来:

const jwt = `${encodedHeader}.${encodedPayload}.${signature}`

API认证

这可能是使用JWT的唯一明智的方法。

常见的情况是:您注册服务并从服务仪表板上下载JWT。从现在开始,您将使用此身份验证对服务器的所有请求。

相反,另一个用例是在管理API和客户端连接到您时发送JWT,并且您希望您的用户仅通过传递令牌来发送后续请求。

在这种情况下,客户端需要将令牌存储在某处。最好的地方在哪里?在HttpOnly cookie。其他方法都容易XSS攻击,因此应避免。无法从JavaScript访问HttpOnly cookie,它会在每次请求时自动发送到原始服务器,因此非常适合用例。

选择最好的JWT库

根据您使用的语言和环境,您可以从许多库中进行选择。最受欢迎的列出了jwt.io网站。

不要将JWT用作会话令牌

您不应将JWT用于会话。使用常规的服务器端会话机制,因为它效率更高且不太容易暴露数据。

资源

阅读更多

互联网上有很多有关JWT的文献。

您可能会浪费大量时间阅读博客文章和意见。其中一些职位是