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,
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 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.
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 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):
I have the following middleware:
class TestMiddleware():
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
print(getattr(request, "user", None))
return self.get_response(request)
The print function always prints None. I added the middleware both before and after the django.contrib.auth.middleware.AuthenticationMiddleware line in settings.py, but in either case, I get None. Also, I'm logged in as a user.
What else can I try? I'm using Django 1.11.
Your middleware should be after 'django.contrib.auth.middleware.AuthenticationMiddleware' if you want to access the user. You don't need to use getattr, just request.user should work. Depending on whether you are logged in or not, it will be the logged-in user or an AnonymousUser.