Search code examples
pythondjangodjango-rest-frameworkdjango-authenticationdjango-middleware

In Django, how to set value in request object in decorator function and access it from request object in decorated function


I have implemented backend api using django. Environment details are as-

Environment : platform : Linux (ubuntu) framework : Django 1.11.28 programming language : python 2.7.12 (will planning to migrate 3.8 in future) Database : Mongodb 3.4

Description : I have developed web services using django. These are plain web services not Restful( earlier there wasn't full support for mongodb for Django rest framework) hence most of the things are customised not as per django standard.

Issue details : For authentication I am using Azure AD. I have written simple decorator which receives access token from request sent by front web app/mobile then this decorator validates token and return to view.For authentication I am using django-auth-adfs package

decorator

authorisation.py

def is_authorized(function):
    @wraps(function)
    def authorize(request, *args, **kwargs):
        # access token validation logic
        if validated(token):
            # get user details from access token first_name, last_name etc
            user_info = {"first_name":"foo","last_name":"bar"}
            return function(request, *args, **kwargs)
        else:
            return HttpResponse('Unauthorized', status=401)
return authorize

View.py

@is_authorized
def home_view(request):
    # calling function which decodes access token and return user details.
    # This function contains same code as in decorator except function it returns user_info
    **first_name, last_name = get_userinfo_from_access_token(request)**
return JsonResponse({"data":{"fname":first_name,"lname":last_name}})

As you can see code got messy, and repetitive code. Here in view I am not able to access user details which already decoded in view. To get user details I wrote same code in get_userinfo_from_access_token() function by passing request object, I don't think this is not near 'ok'.

  • I need approach which is as per django standard and followed by most of the django developers. Do I require to implement some authentication backend or some django middleware if yes please guide me through it.

Considering my current scenario and environment,

  1. Can you explain best and standard approach to access user details from request object
  2. There are lot of views created by me, I am adding is_authorized decorator to every view. Is there any standard and better approach to protect view.
  3. I am planning to rewrite whole code in future using django rest framework. I will be very thankful if anyone provide me some reference or guideline to achieve restful web services so that I can use my existing code and reduce my efforts.

Please let me know if I am unclear about anything and more details required. Thanks in advance.


Solution

  • Well. Let me give your answer sequentially.

    1. Write a middle-ware and attach the user based on token from database query.
    2. Create another middle-ware that will allow protected path only if user is authenticated by above (1) middle-ware.
    3. As django is changing day by day, it will better if you ask separate question when you will be implementing at REST. I know the standard but answering it now may obsolete later.

    Now going back to middle-wares. Middle-ware works in order. Invalid order of those may not work

    1st middle-ware

    class UserResolverMiddleware(MiddlewareMixin):
        """
        A middleware class that adds a ``user`` attribute to the current request.
        """
    
        def process_request(self, request):
            """
    
            get token from request header
            validate token
            decode the token
            query on db or attach a fake user with necessary decoded data. 
            attach user object to request like request.user = user
            """
    

    2nd one.

    from django.http import HttpResponseForbidden
    class ProtectedViewMiddleware(MiddlewareMixin):
    
    
        def process_request(self, request):
    
            """
            create a list of URL which is not protected (e.g: login, forget password)
            unprotected_list = ['']
            if request url does not belongs to unprotected_list and request has no attribue user:
    
                return  HttpResponseForbidden()
            return 
            """