I am logging user login information including OS, browser, ip, and device. And I want to delete it after 30 days of no activity period. The thing is my users use smartphones and they hardly re-login once they logged in. I overrided graphql_jwt.JSONWebTokenMutation like this:
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)
But I soon found a problem. The last login time only gets updated when users login, as I mentioned above. So I cannot delete UserLoginInfo past 30 days. So how should I update last active time of an user using graphql jwt?
I include a JWT token in Authorization header for every single request that requires authentication. And it is handled automatically by graphql_jwt. All I do is using @login_required decorator. But I want to override the resolver for @login_required.
The best place to update user's last active time is middleware because every request made goes through it so you can be confident that any activity is tracked.
E.g. overriding the login_required
decorator would only affect endpoints where it is used and if multiple such decorated endpoints is used to resolve a graphql query every of them would access db to update a last active time so it would result in unnecessary server load.
Django last active middleware example:
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
Include it after authentication middleware:
MIDDLEWARE = [
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
'your_package.middleware.UpdateLastActivityMiddleware',
...
]
Note: it is not graphene middleware bacause it is called on every field resolution, but last activity should be updated once per request (that is exactly what django middleware provides).