如何使用graphql JWT跟踪用户的上次活动时间?

时间:2019-07-17 15:14:14

标签: django jwt graphene-python

我正在记录用户登录信息,包括操作系统,浏览器,IP和设备。我想在30天无活动期后将其删除。问题是我的用户使用智能手机,登录后几乎不重新登录。我这样覆盖了graphql_jwt.JSONWebTokenMutation:

class ObtainJSONWebToken(graphql_jwt.JSONWebTokenMutation):
    class Arguments:
        push_token = graphene.String()

    user = graphene.Field(UserType)

    @classmethod
    def resolve(cls, root, info, push_token=None, **kwargs):
        ip, is_routable = get_client_ip(info.context, ['HTTP_X_FORWARDED_FOR', 'X_FORWARDED_FOR', 'REMOTE_ADDR'])
        ua_string = info.context.META['HTTP_USER_AGENT']
        user_agent = parse(ua_string)
        if user_agent.is_pc is True:
            device = 'Desktop'
        else:
            device = user_agent.device.family
        OS = user_agent.os.family + ' ' + user_agent.os.version_string
        browser = user_agent.browser.family + ' ' + user_agent.browser.version_string

        try:
            login_info = models.UserLoginInfo.objects.get(user=info.context.user, ip=ip, device=device,
                push_token=push_token, OS=OS, browser=browser)
            login_info.save()
        except models.UserLoginInfo.DoesNotExist:
            if push_token is not None:
                try:
                    duplicated_push_token_info = models.UserLoginInfo.objects.get(push_token=push_token)
                    duplicated_push_token_info.push_token = None
                    duplicated_push_token_info.save()
                except models.UserLoginInfo.DoesNotExist:
                    pass
            print(ip, device, OS, browser)
            login_info = models.UserLoginInfo(user=info.context.user, ip=ip, device=device,
                push_token=push_token, OS=OS, browser=browser)
            login_info.save()
        info.context.user.last_login = login_info.last_login
        info.context.user.save()

        return cls(user=info.context.user)

但是我很快发现了一个问题。如上所述,上一次登录时间仅在用户登录时才更新。因此,我无法在30天内删除UserLoginInfo。那么我该如何使用graphql jwt更新用户的上次激活时间?

我为需要身份验证的每个请求在Authorization标头中包含一个JWT令牌。并由graphql_jwt自动处理。我所做的就是使用@login_required装饰器。但是我想为@login_required覆盖解析器。

1 个答案:

答案 0 :(得分:0)

更新用户的上次激活时间的最佳位置是中间件,因为每个请求都会通过它,因此您可以确信可以跟踪任何活动。

例如覆盖login_required装饰器只会影响使用装饰器的端点,如果使用多个这样装饰的端点来解析graphql查询,则每个装饰器端点都将访问db以更新上次活动时间,因此将导致不必要的服务器负载。

Django最后一个活动中间件示例:

class UpdateLastActivityMiddleware(object):
   def __init__(self, get_response):
      self.get_response = get_response

   def __call__(self, request):
      if request.user.is_authenticated:
         User.objects.filter(pk=request.user.id) \
                     .update(last_activity=timezone.now())
      response = self.get_response(request)

      return response

在身份验证中间件之后包含它:


MIDDLEWARE = [
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'your_package.middleware.UpdateLastActivityMiddleware',
    ...
]

注意:它不是石墨烯中间件,因为它是在每个字段分辨率上调用的,但是上一个活动应按请求更新一次(这正是django中间件提供的功能) )。