每次使用 django-graphql-jwt 生成新令牌时,如何撤销 JWT?
How do I revoke JWT everytime a new token generated using django-graphql-jwt?
我正在使用 django-graphql-jwt (https://django-graphql-jwt.domake.io/en/latest/index.html) 来处理我的 Django Python Graphene 应用程序的身份验证。目前,每次生成新的 JWT,只要没有超过其到期时间,之前的 JWT 仍然处于活动状态。
我想在生成新的 JWT 时revoke/prevent 访问以前生成的 JWT(即使 JWT 尚未过期)。
我在想的是利用 JWT 负载中的 origIat 并将其与用户模型中的 last_login 属性进行比较。不过我注意到,每当我使用 JWT 进行身份验证时,User.last_login 都不会更新。
仍在寻找如何正确解决这个问题,想知道你们中是否有人已经解决了这个问题。
谢谢!
我目前的解决方案:
- 向用户模型添加 last_jwt_iat 字段
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(unique=True, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
last_jwt_iat = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f'{self.email}'
- 子类化 graphql_jwt.relay.JSONWebTokenMutation,并在请求新令牌时更新 User.last_jwt_iat
class ObtainJSONWebToken(graphql_jwt.relay.JSONWebTokenMutation):
@classmethod
def resolve(cls, root, info, **kwargs):
# Update User.last_jwt_iat by generating current UTC timestamp
# Probably better if we can extract the origIat from GraphQL payload
user = info.context.user
last_jwt_iat = datetime.datetime.utcnow()
user.last_jwt_iat = last_jwt_iat
user.save()
return cls()
- 使用 Graphene 中间件检查是否 User.last_jwt_iat > 当前 JWT 的 iat
def _authenticate(request):
"""
Check if user is anonymous and JWT authorization header exist
:param request: HttpRequest instance
:return: Boolean
"""
is_anonymous = not hasattr(request, 'user') or request.user.is_anonymous
return is_anonymous and get_http_authorization(request) is not None
class AuthCheckIat(object):
def resolve(self, next, root, info, **args):
context = info.context
# Check if User.last_jwt_iat > token iat, raise error, stop evaluation
if _authenticate(context):
jwt_decoded = jwt_decode(get_http_authorization(context))
username = jwt_decoded['username']
user = User.objects.get(username=username)
iat = datetime.datetime.fromtimestamp(jwt_decoded['origIat'], tz=datetime.timezone.utc)
if user.last_jwt_iat > iat:
raise PermissionDenied(
'User last JWT issued time is greater than supplied JWT issued time. Please use newer token. ')
return next(root, info, **args)
这是我的解决方案
from django.dispatch import receiver
from django.db.models.signals import post_save
from graphql_jwt.refresh_token.models import RefreshToken
@receiver(post_save, sender=RefreshToken)
def clear_tokens(sender, instance, **kwargs):
recent_issued_token = instance
try:
token_user = RefreshToken.objects.get(token=recent_issued_token).user
user_all_tokens = RefreshToken.objects.filter(user=token_user)
tokens_length = len(user_all_tokens)
if tokens_length > 1:
tokens_to_delete = user_all_tokens[0:tokens_length - 1]
for token in tokens_to_delete:
token.delete()
except Exception as e:
print(e)
print('Error deleting existing tokens')
我正在使用 django-graphql-jwt (https://django-graphql-jwt.domake.io/en/latest/index.html) 来处理我的 Django Python Graphene 应用程序的身份验证。目前,每次生成新的 JWT,只要没有超过其到期时间,之前的 JWT 仍然处于活动状态。
我想在生成新的 JWT 时revoke/prevent 访问以前生成的 JWT(即使 JWT 尚未过期)。
我在想的是利用 JWT 负载中的 origIat 并将其与用户模型中的 last_login 属性进行比较。不过我注意到,每当我使用 JWT 进行身份验证时,User.last_login 都不会更新。
仍在寻找如何正确解决这个问题,想知道你们中是否有人已经解决了这个问题。
谢谢!
我目前的解决方案:
- 向用户模型添加 last_jwt_iat 字段
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(unique=True, null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
last_jwt_iat = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f'{self.email}'
- 子类化 graphql_jwt.relay.JSONWebTokenMutation,并在请求新令牌时更新 User.last_jwt_iat
class ObtainJSONWebToken(graphql_jwt.relay.JSONWebTokenMutation):
@classmethod
def resolve(cls, root, info, **kwargs):
# Update User.last_jwt_iat by generating current UTC timestamp
# Probably better if we can extract the origIat from GraphQL payload
user = info.context.user
last_jwt_iat = datetime.datetime.utcnow()
user.last_jwt_iat = last_jwt_iat
user.save()
return cls()
- 使用 Graphene 中间件检查是否 User.last_jwt_iat > 当前 JWT 的 iat
def _authenticate(request):
"""
Check if user is anonymous and JWT authorization header exist
:param request: HttpRequest instance
:return: Boolean
"""
is_anonymous = not hasattr(request, 'user') or request.user.is_anonymous
return is_anonymous and get_http_authorization(request) is not None
class AuthCheckIat(object):
def resolve(self, next, root, info, **args):
context = info.context
# Check if User.last_jwt_iat > token iat, raise error, stop evaluation
if _authenticate(context):
jwt_decoded = jwt_decode(get_http_authorization(context))
username = jwt_decoded['username']
user = User.objects.get(username=username)
iat = datetime.datetime.fromtimestamp(jwt_decoded['origIat'], tz=datetime.timezone.utc)
if user.last_jwt_iat > iat:
raise PermissionDenied(
'User last JWT issued time is greater than supplied JWT issued time. Please use newer token. ')
return next(root, info, **args)
这是我的解决方案
from django.dispatch import receiver
from django.db.models.signals import post_save
from graphql_jwt.refresh_token.models import RefreshToken
@receiver(post_save, sender=RefreshToken)
def clear_tokens(sender, instance, **kwargs):
recent_issued_token = instance
try:
token_user = RefreshToken.objects.get(token=recent_issued_token).user
user_all_tokens = RefreshToken.objects.filter(user=token_user)
tokens_length = len(user_all_tokens)
if tokens_length > 1:
tokens_to_delete = user_all_tokens[0:tokens_length - 1]
for token in tokens_to_delete:
token.delete()
except Exception as e:
print(e)
print('Error deleting existing tokens')