【问题标题】:How do I revoke JWT everytime a new token generated using django-graphql-jwt?每次使用 django-graphql-jwt 生成新令牌时,如何撤销 JWT?
【发布时间】:2020-11-17 23:34:45
【问题描述】:

我正在使用 django-graphql-jwt (https://django-graphql-jwt.domake.io/en/latest/index.html) 来处理我的 Django Python Graphene 应用程序的身份验证。目前,每次生成新的 JWT 时,只要未超过到期时间,之前的 JWT 仍然处于活动状态。

每当我生成新的 JWT 时,我都想撤销/阻止对之前生成的 JWT 的访问(即使 JWT 尚未过期)。

我在想的是利用 JWT 有效负载中的 origIat 并将其与 User 模型中的 last_login 属性之类的东西进行比较。不过我注意到,每当我使用 JWT 进行身份验证时,User.last_login 都不会更新。

仍在寻找如何正确解决这个问题,并想知道你们之前是否已经解决过这个问题。

谢谢!

【问题讨论】:

    标签: django graphql jwt graphene-python graphene-django


    【解决方案1】:

    我目前的解决方案:

    1. 将 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}'
    
    1. 子类化 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()
    
    1. 使用 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)
    

    【讨论】:

      【解决方案2】:

      这是我的解决方案

      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')
      

      【讨论】:

        猜你喜欢
        • 2015-11-02
        • 2017-06-25
        • 2015-12-13
        • 2015-05-06
        • 2016-06-16
        • 2018-02-18
        • 2020-08-03
        • 2017-11-09
        相关资源
        最近更新 更多