Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override Django authentication with middleware

I have a Django website and a MyBB forum, and I'd like to share authentication between them. My website used to be a message board; then I built a few other sections in Django, and both MyBB and Django run on the same domain. I've set up a system where upon registration (on the forum) every user gets two users: a Django user and a MyBB user. Users use the forum to log in, so I need Django to read MyBB's cookies and set the corresponding Django account as the logged user.

Can I do that with a middleware? This middleware would read MyBB's cookies (which contain the id of the MyBB user) and set request.user to the corresponding Django user. I'm new to Django, and I'm not sure if setting request.user (or calling authenticate) in a middleware is a good idea (or if there are better ways to do it).

like image 505
ySgPjx Avatar asked Nov 12 '12 00:11

ySgPjx


People also ask

What is authentication middleware in Django?

If request.user is not authenticated, then this middleware attempts to authenticate the username passed in the ``REMOTE_USER`` request header. If authentication is successful, the user is automatically logged in to persist the user in the session. The header used is configurable and defaults to ``REMOTE_USER``.

How do I use Django middleware?

Activating middleware To activate a middleware component, add it to the MIDDLEWARE list in your Django settings. A Django installation doesn't require any middleware — MIDDLEWARE can be empty, if you'd like — but it's strongly suggested that you at least use CommonMiddleware .

How does Django handle user authentication?

The Django authentication system handles both authentication and authorization. Briefly, authentication verifies a user is who they claim to be, and authorization determines what an authenticated user is allowed to do. Here the term authentication is used to refer to both tasks.


2 Answers

If the user_id stored in your MyBB cookie represents the same user in Django database then you can get the user object straight from that id using default Django backend. If those IDs don't match you need custom backend to get the Django user object. To get the user ID from MyBB cookie and update the user based on it, you need to have a custom authentication middleware.

Middleware

The main idea is to fetch the user object (based on your authentication logic) and assign it to request.user. Here is one example (not tested).

from django.contrib import auth

class MyBBMiddleware:
    def process_request(self, request):
        user_cookie_name = "session_key"
        if user_cookie_name not in request.COOKIES:
            # log user out if you want
            return 
        id = request.COOKIES.get(user_cookie_name)
        # this will find the right backend
        user = auth.authenticate(id) 
        request.user = user
        # if you want to persist this user with Django cookie do the following
        #auth.login(request, user)

Keep in mind that this is called for every request sent to your Django site. For performance you could cache the user and/or do a lazy object trick, EXAMPLE.

Backend

If you need to write your own logic for fetching user object and authenticating a user, you could do the following.

class MyBBCookieBackend(object):
    def authenticate(self, user_id):
        return self.get_user(user_id)
    def get_user(self, user_id):
        # if user_id is not the same in Django and MyBB tables, 
        #  you need some logic to relate them and fetch Django user
        try:
            #TODO your custom logic
            user = User.objects.get(id=user_id)
            return user
        except User.DoesNotExist:
            return None

You need to add your custom backend and middleware in the site settings file.

like image 66
maulik13 Avatar answered Nov 15 '22 10:11

maulik13


I think the right thing to will be a combination of middleware and a Django authentication backend.

Your middleware will call the backend's authenticate() with possibly the user id as a keyword argument. You authentication backend in turn will call the corresponding authenticate() method and return a user object.

class MiddlewareTracker:
 def process_request(self, request):
    id = request.COOKIES.get('logged_in_id') 
    authenticate(user_id = id)
    return None

class ForumAuthBackend(object):

    def authenticate(self, *args, **kwargs):
        id = kwargs.get('user_id')
        return User.objects.get(id = id)

    def get_user(self, user_id):
        return User.objects.get(id = user_id)

I will also recommend going through this https://docs.djangoproject.com/en/1.2/topics/auth/

like image 22
Siddharth Sarda Avatar answered Nov 15 '22 08:11

Siddharth Sarda