Пользователи Django и аутентификация из внешнего источника - PullRequest
19 голосов
/ 29 июня 2009

У меня есть приложение Django, которое получает свои данные полностью из внешнего источника (запрашивается через HTTP). То есть у меня нет возможности для локальной базы данных. Данные сеанса хранятся в кеше (на моем сервере разработки я использую базу данных SQLite, так что это не источник ошибок). Я использую кровоточащий Django 1.1svn.

Введите проблему: я хочу использовать собственную систему аутентификации Django для пользователей.

Кажется, довольно просто написать свой собственный Аутентификационный Бэкэнд, но всегда только при условии, что у вас есть локальная база данных для сохранения пользователей. Без базы данных моя главная проблема - постоянство.

Я попробовал это со следующим (предположим, что datasource.get() - это функция, которая возвращает какой-то тип dict):

class ModelBackend (object):
    """Login backend."""

    def authenticate (self, username=None, password=None):
        """Check, if a given user/password combination is valid"""

        data = datasource.get ('login', username, password)
        if data and data['ok']:
            return MyUser (username=username)
        else:
            raise TypeError
            return None

    def get_user (self, username):
        """get data about a specific user"""

        try:
          data = datasource.get ('userdata', username)
          if data and data['ok']:
              return data.user
        except:
            pass
        return None


class MyUser (User):
    """Django user who isn't saved in DB"""

    def save (self):
        return None

Но преднамеренно отсутствующий метод save() в MyUser, похоже, нарушает хранение сеанса для входа в систему.

Как должен выглядеть MyUser без локальной базы данных?

Ответы [ 3 ]

23 голосов
/ 02 июля 2009

ОК, это намного сложнее, чем я думал. Во-первых, начните с http://docs.djangoproject.com/en/dev/howto/auth-remote-user/,, но вам нужно расширить его с помощью своего собственного бэкенда и пользователя.

from django.contrib.auth.backends import RemoteUserBackend

class MyRemoteUserBackend (RemoteUserBackend):
    # Create a User object if not already in the database?
    create_unknown_user = False

    def get_user (self, user_id):
        user = somehow_create_an_instance_of (MyUser, user_id)
        return user

    def authenticate (self, **credentials):
        check_credentials ()
        user = somehow_create_an_instance_of (MyUser, credentials)
        return user

Тогда пользователь:

from django.contrib.auth.models import User

class MyUser (User):

    def save (self):
        """saving to DB disabled"""
        pass

    objects = None # we cannot really use this w/o local DB

    username = ""  # and all the other properties likewise.
                   # They're defined as model.CharField or similar,
                   # and we can't allow that

    def get_group_permissions (self):
        """If you don't make your own permissions module,
           the default also will use the DB. Throw it away"""
        return [] # likewise with the other permission defs

    def get_and_delete_messages (self):
        """Messages are stored in the DB. Darn!"""
        return []

Уф! Django действительно не предназначен для использования без базы данных ...

4 голосов
/ 27 сентября 2013

Вместо перезаписи метода save вы также можете отключить сигнал, который его вызывает. Это то, что я делаю в некоторых приложениях, которые имеют доступ только для чтения к базе данных пользователей.

# models.py (for instance)
from django.contrib.auth.models import update_last_login, user_logged_in
user_logged_in.disconnect(update_last_login)
1 голос
/ 01 июля 2009

grep ping из источника показал, что на самом деле вызывается единственное место user.save() (кроме кода создания пользователя и кода управления паролем, который вам вообще не нужен) - django.contrib.auth.login(), для обновления user.last_login значение.

# TODO: It would be nice to support different login methods, like signed cookies.
user.last_login = datetime.datetime.now()
user.save()

Если вы не хотите, чтобы пользовательские данные оставались в БД, попробуйте добавить фиктивный метод save(). Если я прав, это должно сработать.

def save(self, *args, **kwargs):
    pass

Конечно, поскольку у вас вообще нет персистентности, вам следует рассмотреть кэширование результатов datasource.get, в противном случае в худшем случае вы можете снова и снова запрашивать данные при каждом входе пользователя в систему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...