注销 Django Rest Framework JWT
Logout Django Rest Framework JWT
我想问一下,在我使用 JWT 时注销是否是个好主意。
为了登录,我发送了一个带有用户名和密码的 post 请求以获取所需的令牌(保存到 localStorage 中),当然,这将允许我向需要令牌的视图发送更多请求。
但我不确定应该如何注销用户。我可以清除 localStorage,但令牌仍然可用。
所以,我想问一下我是否应该使用刷新令牌,因为我无法禁用它。
您发布的每个 JWT 都应该有一个到期日期时间,因此每当您注销用户时,您应该从本地存储 cookie 中删除 jwt-token。
but the token remains available.
不确定上面这行是什么意思,但您不必担心从本地存储和 cookie 中清除令牌后用户是否仍然可以使用该令牌,因为无论哪种方式,它都会在到期日期后失效。
你是对的,即使你删除了 JWT 令牌,它在一段时间内仍然有效,直到它过期。 JWT 是无状态的。因此,如果你想处理注销和使令牌无效,你必须需要保留一个数据库或内存缓存来存储无效(列入黑名单的)令牌。然后你需要添加一个新的权限来检查令牌是否被列入黑名单。
class BlackListedToken(models.Model):
token = models.CharField(max_length=500)
user = models.ForeignKey(User, related_name="token_user", on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ("token", "user")
class IsTokenValid(BasePermission):
def has_permission(self, request, view):
user_id = request.user.id
is_allowed_user = True
token = request.auth.decode("utf-8")
try:
is_blackListed = BlackListedToken.objects.get(user=user_id, token=token)
if is_blackListed:
is_allowed_user = False
except BlackListedToken.DoesNotExist:
is_allowed_user = True
return is_allowed_user
您可以在令牌到期后将令牌从黑名单中移除。
您无法在令牌创建后手动使其过期。因此,您实际上不能像在会话中那样在服务器端使用 JWT 注销。
JWT 是无状态的,这意味着您应该将所需的一切存储在有效负载中,并跳过对每个请求执行数据库查询。但是如果你打算有一个严格的注销功能,不能等待令牌自动过期,即使你已经从客户端清除了令牌,那么你可能需要忽略无状态逻辑并进行一些查询。那么解决方案是什么?
设置合理的代币到期时间
注销后从客户端删除存储的令牌
针对每个授权请求黑名单查询提供的令牌
黑名单
所有不再有效且尚未过期的令牌的“黑名单”。您可以在文档上使用具有 TTL 选项的数据库,该选项将设置为令牌过期前的剩余时间。
Redis
Redis 是 blacklist 的一个很好的选择,它将允许在内存中快速访问列表。然后,在针对每个授权请求运行的某种中间件中,您应该检查提供的令牌是否在 Blacklist 中。如果是,你应该抛出一个未经授权的错误。如果不是,则放手,JWT 验证将处理它并确定它是否已过期或仍然有效。
有关详细信息,请参阅 How to log out when using JWT。通过 Arpy Vanyan
我想问一下,在我使用 JWT 时注销是否是个好主意。 为了登录,我发送了一个带有用户名和密码的 post 请求以获取所需的令牌(保存到 localStorage 中),当然,这将允许我向需要令牌的视图发送更多请求。
但我不确定应该如何注销用户。我可以清除 localStorage,但令牌仍然可用。
所以,我想问一下我是否应该使用刷新令牌,因为我无法禁用它。
您发布的每个 JWT 都应该有一个到期日期时间,因此每当您注销用户时,您应该从本地存储 cookie 中删除 jwt-token。
but the token remains available.
不确定上面这行是什么意思,但您不必担心从本地存储和 cookie 中清除令牌后用户是否仍然可以使用该令牌,因为无论哪种方式,它都会在到期日期后失效。
你是对的,即使你删除了 JWT 令牌,它在一段时间内仍然有效,直到它过期。 JWT 是无状态的。因此,如果你想处理注销和使令牌无效,你必须需要保留一个数据库或内存缓存来存储无效(列入黑名单的)令牌。然后你需要添加一个新的权限来检查令牌是否被列入黑名单。
class BlackListedToken(models.Model):
token = models.CharField(max_length=500)
user = models.ForeignKey(User, related_name="token_user", on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ("token", "user")
class IsTokenValid(BasePermission):
def has_permission(self, request, view):
user_id = request.user.id
is_allowed_user = True
token = request.auth.decode("utf-8")
try:
is_blackListed = BlackListedToken.objects.get(user=user_id, token=token)
if is_blackListed:
is_allowed_user = False
except BlackListedToken.DoesNotExist:
is_allowed_user = True
return is_allowed_user
您可以在令牌到期后将令牌从黑名单中移除。
您无法在令牌创建后手动使其过期。因此,您实际上不能像在会话中那样在服务器端使用 JWT 注销。
JWT 是无状态的,这意味着您应该将所需的一切存储在有效负载中,并跳过对每个请求执行数据库查询。但是如果你打算有一个严格的注销功能,不能等待令牌自动过期,即使你已经从客户端清除了令牌,那么你可能需要忽略无状态逻辑并进行一些查询。那么解决方案是什么?
设置合理的代币到期时间
注销后从客户端删除存储的令牌
针对每个授权请求黑名单查询提供的令牌
黑名单
所有不再有效且尚未过期的令牌的“黑名单”。您可以在文档上使用具有 TTL 选项的数据库,该选项将设置为令牌过期前的剩余时间。
Redis
Redis 是 blacklist 的一个很好的选择,它将允许在内存中快速访问列表。然后,在针对每个授权请求运行的某种中间件中,您应该检查提供的令牌是否在 Blacklist 中。如果是,你应该抛出一个未经授权的错误。如果不是,则放手,JWT 验证将处理它并确定它是否已过期或仍然有效。
有关详细信息,请参阅 How to log out when using JWT。通过 Arpy Vanyan