Search code examples
djangodjango-authentication

Django's Custom Authentication Middleware & Authentication Backend


I'm writing a custom Authentication middleware that check the incoming requests for the "Authorization" key in the header, which contains a token.

I'm using this token to check with a third-party (Microsoft Graph) for the validity of the user. MS Graph will respond with an object like below

# the response object

{
    '@odata.context': 'https://graph.microsoft.com/v1.0/$metadata#users/$entity',
    'businessPhones': ['xxx'],
    'displayName': 'xxx',
    'givenName': 'xxx',
    'id': 'xxx',
    'jobTitle': None,
    'mail': 'xxx',
    'mobilePhone': None,
    'officeLocation': None,
    'preferredLanguage': 'xxx',
    'surname': 'xxx',
    'userPrincipalName': 'xxx'
}

EDIT: Adding custom middleware code here:

class AuthenticationMiddleware(MiddlewareMixin):
    if not request.user.is_authenticated:
        if "Authorization" in request.headers:
            # Make a request to MS Graph with the given token
            # to get user details and append to request
            token = request.headers["Authorization"]
        elif "accessToken" in request.GET:
            token = request.GET["accessToken"]
        else:
            token = None

        if token:
            url = "https://graph.microsoft.com/v1.0/me/"
            payload = {}
            headers = {"Authorization": "Bearer {}".format(token)}
            response = requests.request("GET", url, headers=headers, data=payload)
            if response.ok:
                request.custom_user = response.json()
            else:
                request.custom_user = AnonymousUser
        else:
            request.custom_user = AnonymousUser

Now I want to design this to work just like Django's default authentication backend with proper group and permission. How can I work on a LazyObject to be able to check for user's group membership and permission?

UPDATE

It looks like there's also a custom backend authentication that works like this.

Is it doing the same thing as I'm doing with the middleware?

from django.contrib.auth.backends import BaseBackend

class MyBackend(BaseBackend):
    def authenticate(self, request, token=None):
        # Check the token and return a user.
        ...

Solution

  • you should custom an Middleware like the below, and add it to middlewares in settings

    class SimpleMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
            # One-time configuration and initialization.
    
        def __call__(self, request):
            # Code to be executed for each request before
            # the view (and later middleware) are called.
    
            response = self.get_response(request)
    
            # todo: do something you want in response 
            return response
    

    see also:https://docs.djangoproject.com/en/3.1/topics/http/middleware/

    EDIT:

    Is it doing the same thing as I'm doing with the middleware?

    no, it's not.

    the most different is that The backend is used for connecting with database, and the middleware is aim to process the request. You can find more examples code in django.middleware package.

    and if you want to custome how to save the infomation to database eg: customer the authenticate method, you should customer a backend for the work. otherwise you may custome an middleware to process all of the requests. Because it is easy to customize middleware.