Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django JWT authentication - user is anonymous in middleware

I am using Django JWT to power up authentication system in my project. Also, I have a middleware, and the problem is that inside it, the user is anonymous for some reason, while in the view I am able to access the correct user by request.user. This issue is driving me crazy because some time ago this code worked perfectly ! Is this JWT's bug or I am doing something wrong ?

class TimezoneMiddleware(MiddlewareMixin):
         def process_request(self, request):
            # request.user is ANONYMOUS HERE !!!!
            if not request.user.is_anonymous:
                  tzname = UserProfile.objects.get(user = request.user).tz_name
                  if tzname:
                       timezone.activate(pytz.timezone(tzname))

Relevant settings.py module:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'djangorestframework_camel_case.render.CamelCaseJSONRenderer',
        # Any other renders
    ),

    'DEFAULT_PARSER_CLASSES': (
        'djangorestframework_camel_case.parser.CamelCaseJSONParser',
        # Any other parsers
    ),
}

JWT_AUTH = {
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',

    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',

    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',

    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

    'JWT_RESPONSE_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_response_payload_handler', 
    # 'rest_authentication.views.jwt_response_payload_handler',
    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': False,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,
    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}

I have also come across resources which helped me to retrieve the actual user, BUT ! I am still unable to set the timezone (timezone.activate(pytz.timezone(tzname)) seems to be ignored.

like image 251
Edgar Navasardyan Avatar asked Jun 11 '18 08:06

Edgar Navasardyan


People also ask

How does Django JWT authentication work?

JWT Authentication Workflow One of them is an Access Token and the other is a Refresh Token. The frontend of your application then stores the tokens securely and sends the Access Token in the Authorization header of all requests it then sends to the server. An HTTP Request containing JWT in the Authorization header.

What is middleware authentication in Django?

In Django, middleware is a small plugin that runs in the background while the request and response are being processed. The application's middleware is utilized to complete a task. Security, session, csrf protection, and authentication are examples of functions.


2 Answers

Yes, this issue is due to the JWT. You can checkout the discussion for it https://github.com/GetBlimp/django-rest-framework-jwt/issues/45 To fix this you will have to create a custom middleware which will set the request.user. Here is one I am using in my code:

from django.contrib.auth.middleware import get_user
from django.utils.functional import SimpleLazyObject
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


class JWTAuthenticationMiddleware(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

Include this in the middlewares. It should come above all the middlewares which are using request.user.

like image 194
Atul Mishra Avatar answered Nov 25 '22 13:11

Atul Mishra


@Atul Mishra: Thank you! Changed your version to the newest drf-jwt package (1.17.2). Seems like the the current github repository moved from this to here

from django.contrib.auth.middleware import get_user
from django.utils.functional import SimpleLazyObject
from rest_framework_jwt.authentication import JSONWebTokenAuthentication


class JWTAuthenticationInMiddleware(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):
        # Already authenticated
        user = get_user(request)
        if user.is_authenticated:
            return user

        # Do JTW authentication
        jwt_authentication = JSONWebTokenAuthentication()

        authenticated = jwt_authentication.authenticate(request)
        if authenticated:
            user, jwt = authenticated

        return user
like image 33
user1383029 Avatar answered Nov 25 '22 13:11

user1383029