I am using Django REST Framework alongside with rest_framework_simplejwt and trying to write my own middleware, that will update user.last_request every time user performs one.
from django.utils.timezone import now
class LastRequestMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if request.user.is_authenticated:
request.user.last_request = now()
request.user.save()
response = self.get_response(request)
return response```
But every time `user.is_authenticated` returns `False'
The easiest way I found to fix this problem is to authenticate user inside middleware manually. New code looks like this:
from django.utils.timezone import now
from rest_framework_simplejwt.authentication import JWTAuthentication
class LastRequestMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
user = JWTAuthentication().authenticate(request)[0]
if user:
user = user[0]
if user.is_authenticated:
user.last_request = now()
user.save(update_fields=['last_request'])
response = self.get_response(request)
return response
This is an easy-fix, so if you need user authentication functionality in many middlewares, consider using separate AuthMiddleware for SimpleJWT authentication.
Related
I have a middleware in my app that sets the currently logged in user. On my local machine, get_current_user() works fine, but it seems to return None when the app is run in a kubernetes container. What am I missing?:
USER_ATTR_NAME = getattr(settings, "LOCAL_USER_ATTR_NAME", "_current_user")
_thread_locals = local()
def _do_set_current_user(user_fun):
setattr(_thread_locals, USER_ATTR_NAME, user_fun.__get__(user_fun, local))
def _set_current_user(user=None):
"""
Sets current user in local thread.
Can be used as a hook e.g. for shell jobs (when request object is not
available).
"""
_do_set_current_user(lambda self: user)
class SelfServeCurrentUserMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# request.user closure; asserts laziness;
# memorization is implemented in
# request.user (non-data descriptor)
_do_set_current_user(lambda self: getattr(request, "user", None))
response = self.get_response(request)
return response
def get_current_user():
current_user = getattr(_thread_locals, USER_ATTR_NAME, None)
if callable(current_user):
return current_user()
return current_user
def get_current_authenticated_user():
current_user = get_current_user()
if isinstance(current_user, AnonymousUser):
return None
return current_user
all what you do shows me - you don't really understand, how Django works.
What i mean:
You need User model, somewhere, probably it is form. You don't understand, how to get a user there, and you try to use locals. You made a import of functions get_current_user, get_current_authenticated_user. Now you can achieve a User. This is wrong for Django, but you can do it.
i have a small trick for you in this case:
from django.utils.translation.trans_real import _active as _thread_locals
# _thread_locals = local() you don't need it.
... # other staff
this is what you want. See the commentary about _active in django code
I have Django1.9 middleware class:
class MyMiddleware(object):
def process_request(self, request):
token = self._get_or_create_token(request)
#request.context['token'] = token
The issue is:
- I would like to put token to some sort of context to pass it through the application flow.
- I avoid putting it into request session, because it result in extra database reading/writing.
Could you suggest me some solution?
You can add any attribute to the HttpRequest, so you can implement this with:
class MyMiddleware(object):
def process_request(self, request):
token = self._get_or_create_token(request)
request.token = token
or if you really want some sort of context dictionary:
class MyMiddleware(object):
def process_request(self, request):
token = self._get_or_create_token(request)
if not hasattr(request, 'context'):
request.context = {}
request.context['token'] = token
I have Django1.9 middleware class.
As is documented, django-1.9 is not supported anymore since April 2017, therefore I strongly advice to update.
I want to use request.user in Django Rest Framework custom middleware.
It returns AnnonymousUser and I failed.
I created new Custom middleware which returns real user.
from django.contrib.auth.middleware import get_user
from django.utils.functional import SimpleLazyObject
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
class AuthenticationMiddlewareJWT(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.user = SimpleLazyObject(lambda: self.__class__.get_jwt_user(request))
return self.get_response(request)
#staticmethod
def get_jwt_user(request):
user = get_user(request)
if user.is_authenticated:
return user
jwt_authentication = JSONWebTokenAuthentication()
if jwt_authentication.get_jwt_value(request):
user, jwt = jwt_authentication.authenticate(request)
return user
Above middleware, jwt_authentication.get_jwt_value(request), this returns always None.
How can I fix it and use request.user in custom middleware?
I'm trying to use catch the Django user in the Middleware but without success. Using Python 3.6 and Django 1.11.
from threading import local
_user = local()
class CurrentUserMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
_user.value = request.user
return self.get_response(request)
def get_current_user():
return _user.value
I need to save the request.user outside the class, in the get_current_user(), but it is not working.
Can someone give me a clue why I can't have the _user.value in the get_current_user() ?
The reason I'm doing this is to import to a model
from current_user import get_current_user
Thanks,
I have to override settings in a test in Django
#override_settings(XYZ_REDIRECT="http://localhost:8000")
#override_settings(TOKEN_TIMEOUT=0)
class CustomTestCase(TestCase):
def setUp(self):
self.token = self._generate_auth_token()
self.client = Client()
def test_token_expiry(self):
feoken_count = 0
client = Client()
client.post('/api/v1/auth/login/', {'token': 'AF'})
# Over HERE TOKEN_TIMEOUT is not changed
self.assertEqual(ABCN.objects.count(), feoken_count)
The override settings decorator, however seems not to work. In the other side of the route, I have this code.
from fetchcore_server.settings import AUTH0_SERVER_URL, TOKEN_TIMEOUT
....
def post(self, request, *args, **kwargs):
if 'token' in request.data:
FetchcoreToken.objects.filter(expiry_time__lte=timezone.now()).delete()
print TOKEN_TIMEOUT # this is still original value
token = request.data['token']
try:
fetchcore_token = FetchcoreToken.objects.get(token=token)
user = fetchcore_token.user
user_id = user.id
I tried using the with self.settings(TOKEN_TIMEOUT=0) but even that did not work.
I am not sure how I'm using this wrong
Django docs on the subject: https://docs.djangoproject.com/en/1.11/topics/testing/tools/
In case it is relevant, this is how I run the test
python manage.py test api.tests.integration.v1.users.AuthUserTestCase
You problem is that you are using import of settings directly,
from fetchcore_server.settings import AUTH0_SERVER_URL, TOKEN_TIMEOUT
but you should use settings object provided by django https://docs.djangoproject.com/en/1.11/topics/settings/#using-settings-in-python-code
from django.conf import settings
....
def post(self, request, *args, **kwargs):
if 'token' in request.data:
FetchcoreToken.objects.filter(expiry_time__lte=timezone.now()).delete()
print settings.TOKEN_TIMEOUT # this is still original value
token = request.data['token']
try:
fetchcore_token = FetchcoreToken.objects.get(token=token)
user = fetchcore_token.user
user_id = user.id
Also as a sidenote, you could provide all overloaded settings at once
#override_settings(XYZ_REDIRECT="http://localhost:8000", TOKEN_TIMEOUT=0)
class CustomTestCase(TestCase):