神奇的 JSON Web Tokens(JWT)
JSON Web Tokens (JWT) 是一种无状态处理用户身份验证的方法。 什么意思?
JWT帮助建立认证机制而不将身份验证状态存储在任何存储中,无论是会话内存还是数据库,因此, 当检查用户的身份验证状态时,不需要访问会话内存或执行数据库查询。相反, 根据你选择的用户payload生成token 并在客户端的请求中使用它来标识服务器上的用户 🛂
因此,基本上,每当创建token时,就可以永远使用它,或者直到它过期为止。 JWT生成器可以在生成的时候有一个指定过期时间的选项。
不过你想让已经生成的token失效该怎么办呢?当用户注销或者更改密码的时候你该做些什么呢🤔
注销
通常在使用JWT做身份验证时客户端将token储存在某个地方,并将附加到每个需要身份验证的请求上,所以注销的第一件事就是删除储存在客户端上的token(例如 浏览器本地储存)在这种情况下客户端没有了token请求需要认证的接口自然会得到未认证的响应。不过这就够了吗?这个是防君子不防小人的做法实际上在注销之前通过一些手段将token拿到手在注销后依然可以使用!不信的的话可以自己尝试下。
让我们从后台注销token,你可能会说桥豆麻袋这对于jwt来说并不是那么简单,你并不能像删除cookie和session那样来删除token。
实际上,JWT的目的与session不同,不可能强制删除或失效已经生成的token。
Token 过期
是的 Token 可以设置过期。
在生成token时可以指定过期时间,你可以在有效的paylaod中加上exp字段就像这样:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516234022,
"exp": 1516239022
}
exp 字段为时间戳,这里的iat字段代表发布时间,此Token设置为在发布后5秒过期⏰。
如果你不想拥有永远有效的Token你应该给你的JWT设置一个合理的到期时间,时间的长短取决于你的应用,我们将在这里使用时长为一天Token,并在登录操作中生成它们,对于NodeJS应用程序,代码应该如下所示:
const jwt = require('jsonwebtoken');
const payload = {
"sub": "1234567890",
"name": "John Doe",
"iat": 1516234022
}
const token = jwt.sign(payload, 'your-secret', {expiresIn: '1d'})
当这个token过期时验证器会返回一个error,而且后端一旦收到需要授权的请求,就会以未授权的响应状态进行响应。通常,你将从客户端删除令牌并将用户重定向到登录页面。因此,在这个例子中,所有用户在使用你的应用程序1天后将自动注销。
很酷,但我还是想注销!
如前所述,你不能在Token创建后手动使其过期,你实际上不能像使用session那样在服务器端使用JWT注销🙀或者,除非,你可以…
使用JWT应该是无状态的,这意味着你应该将所需的一切存储在payload中,并跳过对每个请求执行DB查询,但是如果你计划有一个严格的注销功能,无法等待Token自动过期,即使你已经从客户端清除了Token,然后你可能需要违背无状态规则并执行一些查询。
有一种实现可能是,存储一个所谓的“黑名单”所有Token是有效的,还没有到期你可以挑选一个拥有TTL功能的数据库,TTL被用于为Token记录Token过期之前剩余的时间量。Redis
是一个很好的选择,这将允许在内存中快速访问列表,然后,在某个中间件中,运行在每个授权请求上,你应该检查提供的令牌是否在黑名单中🕵️,如果在的话就抛出一个未认证异常,如果没有让它通过,JWT验证将处理它并确定它是否已过期或仍然有效。
结论
似乎,在使用JSON Web令牌时创建干净的注销流程并不那么简单,你应该让Token保持活动状态,直到它自己过期为止;或者,如果你希望在用户注销时限制Token的使用,则选择储存一个Token黑名单。总而言之,只需遵循以下4个要点:
- 设置令牌的合理过期时间
- 注销时从客户端删除存储的Token
- 拥有不再活动Token的数据库,这些Token仍有一些生存时间
- 针对每个请求根据黑名单查询授权情况