JSON网络令牌(JWT)的介绍

229 阅读4分钟

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

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

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

这种架构在现代Web应用中被证明是非常有效的,在用户被认证后,我们会对REST或GraphQL API执行API请求。

谁在使用JWT?例如,谷歌。如果你使用谷歌的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 Node模块

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攻击,因此应该避免。HttpOnly cookie不能从JavaScript中访问,并且在每次请求时都会自动发送到源服务器,所以它完全适合这种使用情况。

选择最好的JWT库

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

不要将JWTs用作会话令牌

你不应该将JWTs用于会话。使用常规的服务器端会话机制,因为它的效率更高,而且不容易发生数据暴露。

资源