The most compatible way to do this would be to create a user Profile model that includes a foreign key to the Site model, then write a custom auth backend that checks the current site against the value of that FK. Some sample code:
Define your profile model, let's say in app/models.py:
from django.db import models
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
site = models.ForeignKey(Site)
Write your custom auth backend, inheriting from the default one, let's say in app/auth_backend.py:
from django.contrib.auth.backends import ModelBackend
from django.contrib.sites.models import Site
class SiteBackend(ModelBackend):
def authenticate(self, **credentials):
user_or_none = super(SiteBackend, self).authenticate(**credentials)
if user_or_none and user_or_none.userprofile.site != Site.objects.get_current():
user_or_none = None
return user_or_none
def get_user(self, user_id):
try:
return User.objects.get(
pk=user_id, userprofile__site=Site.objects.get_current())
except User.DoesNotExist:
return None
This auth backend assumes all users have a profile; you'd need to make sure that your user creation/registration process always creates one.
The overridden authenticate
method ensures that a user can only login on the correct site. The get_user
method is called on every request to fetch the user from the database based on the stored authentication information in the user's session; our override ensures that a user can't login on site A and then use that same session cookie to gain unauthorized access to site B. (Thanks to Jan Wrobel for pointing out the need to handle the latter case.)