Как получить уникальных пользователей на нескольких сайтах Django, работающих на основе "сайтов"?

Я создаю фреймворк сайта Django, который будет использовать несколько независимых сайтов, используя все те же приложения, но со своими собственными шаблонами. Я планирую выполнить это, используя несколько файлов настроек и установив для них уникальный SITE_ID, например, предложенный в документах Django для django.contrib.sites framework

Однако я не хочу, чтобы пользователь с сайта A мог войти на сайт B. После проверки таблицы пользователя, созданной syncdb, я не вижу столбец, который мог бы ограничить пользователя определенным сайтом. Я также попытался создать пользователя "bob" на одном сайте, а затем с помощью команды оболочки перечислить всех пользователей с другой стороны и, конечно же, там появится bob.

Как я могу обеспечить, чтобы все пользователи были ограничены их соответствующими сайтами?

Ответ 1

Наиболее совместимый способ сделать это было бы создать Профиль пользователя модель, которая включает в себя внешний ключ к модели сайта, а затем написать пользовательские аутентификации бэкенд, который проверяет текущий сайт против значения этого FK. Пример кода:

Определите модель своего профиля, скажем, в 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)

Напишите свой собственный сервер аутентификации, наследующий от стандартного, скажем, в 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

Этот auth backend предполагает, что у всех пользователей есть профиль; вам необходимо убедиться, что процесс создания/регистрации пользователя всегда создает его.

Переопределенный метод authenticate гарантирует, что пользователь может войти только на правильный сайт. Метод get_user вызывается для каждого запроса для извлечения пользователя из базы данных на основе сохраненной информации аутентификации в пользовательском сеансе; наше переопределение гарантирует, что пользователь не может войти в системе на сайте А, а затем использовать те же кук сессии, чтобы получить несанкционированный доступ к сайту B. (Спасибо Яна Wrobel за указание на необходимости отрегулировать последний случай.)

Ответ 2

Вы можете подключить собственные учетные записи авторизации и аутентификации, которые учитывают идентификатор сайта.

Смотрите другие источники аутентификации в документации django и аутентификация обратные ссылки

Кроме того, если ваш источник django слишком стар, вы всегда можете самостоятельно изменить код authenticate() или login(). В конце концов... Разве это не одно из чудес с открытым исходным кодом. Имейте в виду, что при этом вы можете повлиять на совместимость с другими модулями.

Надеюсь, что это поможет.

Ответ 3

Вы должны знать, что многие люди жалуются на систему авторизации по умолчанию Django и ее привилегии - у нее просто правила для объектов, для экземпляров объектов - что это значит, что без написания какого-либо кода это не будет возможным.

Однако есть некоторые авторизационные крючки, которые могут помочь вам достичь этой цели, например:

Посмотрите там: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py и для разрешения класса.

Вы можете добавить свое собственное разрешение и определить правила для них (есть ForeignKey для пользователя и для ContentType).

Однако2, без monkeypatching/изменить некоторые методы, это может быть сложно.