Django Remote Authentication без перенаправления

В моем приложении мне нужно аутентифицировать пользователей через мой REST API. Итак, у меня есть форма с полями user / pass, и после ее отправки я бы хотел перейти непосредственно на "следующую" страницу. Очевидно, мне нужно отправить форму через AJAX, так как я не хочу, чтобы меня перенаправляли на страницу API. Но как тогда RemoteUserMiddleware будет знать, что мой пользователь должен пройти аутентификацию, если запрос будет обработан javascript?

1 ответ

Решение

Насколько я понимаю, системная архитектура у вас сейчас выглядит примерно так:

       --------------             -------------------       -------------------
       | client web | ----------> |    REST API     | ----> | db / persistent |
       |   browser  | <---------- | pylons / nodejs | <---- |     storage     |
       --------------             -------------------       -------------------
            ^ |                         ^ | 
            | |                         | |
            | |                         | v 
            | |                   -----------------         -------------------
            | ------------------> |    django     | ------> | db / persistent |
            --------------------- |               | <------ |     storage     |
                                  -----------------         -------------------

Ваш вопрос касается того, как входить и выходить из пользователей в приложении django, когда аутентификация выполняется в веб-приложении REST API.

Я не уверен, что RemoteUserMiddleware это то, что вы ищете, он предназначен для аутентификации на уровне веб-сервера Apache при запуске django с использованием wsgi на этом же сервере. Название относится к REMOTE_USER системная переменная unix, которая является методом аутентификации старой школы в apache.

Кажется неразумным разрешать клиенту быть посредником в цепочке аутентификации между django и вашим REST API, это может показаться небезопасным. Вместо этого django может напрямую вызывать REST API для аутентификации пользователей, а затем создавать соответствующие django.contrib.auth.models.User Объект для локального хранения это выполняется в пользовательском бэкенде аутентификации, смотрите здесь.

Что-то вроде:

from django.contrib.auth.models import User
import requests

class RestBackend(object):
    supports_inactive_user = False

    def authenticate(self, username=None, password=None):
        rest_response = requests.post('http://your.rest.interface/auth', 
            data={ 'username' : username, 'password' : password }).json()

        if rest_response['error'] == 'None':
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                user = User(username=username, password=password)
                user.save()
            return user
        return user

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

При этом библиотека запросов вызывает API REST с синхронным http-запросом для входа пользователя в систему, а затем создает локальный экземпляр объекта User, если он еще не существует. Существуют более сложные протоколы для удаленной аутентификации, если требуется, например, http://oauth.net/2/.

Этот бэкэнд должен быть указан в settings.py файл

AUTHENTICATION_BACKENDS = ('my.classy.django.app.RestBackend')

Тогда ваше приложение Django может использовать authenticate а также login функции в его представлениях, используя http или json, больше информации здесь.

Джанго установит request.user быть объектом класса AnonymousUser пока пользователь не вошел в систему, документы здесь. Это позволяет вам различать этих пользователей в ваших представлениях без использования перенаправлений:

  from django.http import HttpResponse
  from django.utils import simplejson
  from myApp.models impor InfoObject

  def infoPage(request):
        # return info objects for logged in user, or all info objects otherwise
        if request.user.is_authenticated():
            infoObjects = InfoObject.objects.filter(user=request.user).orderby("-pubdate")
        else:
            infoObjects = InfoObject.objects.orderby("-pubdate")
        return HttpResponse(simplejson.dumps(infoObjects), content_type = "application/json") 

или, если вы хотите, чтобы на странице отображалось поле "профиль пользователя", ala stackru:

 # helper function that can be called from all your views
 def getUserInfo(request):
      if request.user.is_authenticated():
          return UserInfo.objects.get(user=user)
      else:
          return []

 def randomPage(request):
       info = getUserInfo(request)
       .....other page logic....
       return HttpResponse('['+simplejson.dumps(..pageData..)+','+simplejson.dumps(info)+']', content_type = "application/json") 

Если вместо этого вы используете шаблоны, а не ajax для рендеринга вашей страницы, тогда эта логика может быть передана в шаблон с областями, появляющимися при входе пользователя в систему, без необходимости использовать перенаправления:

{% extends "base.html" %}

{% block userInfo %}
    <div id="userArea">
    {% if user.is_authenticated %}
        User: {{ user.username }}<br />
        geezer score: {{ userProfile.geezerScore }}<br />
        <input type="button" value="log out" />
    {% else %}
        Username: <input type="text" id="username" />
        password: <input type="password" id="password" />
        <input type="button" value="log in" />
    {% endif %}
    </div>
{% endblock %}

Это основывается на том, что пользовательский объект основан на шаблоне представлением, и потребует JavaScript, чтобы подключить аутентификацию бэкэнда.

Также возможно использовать render_to_string() визуализировать контекст с шаблоном и вернуть его в запрос ajax вместо json. Таким образом, разрешение html будет отображаться на сервере и возвращаться клиенту без необходимости перезагрузки страницы в клиенте.

Таким образом, можно заставить django отображать некоторые шаблоны и использовать некоторые ответы ajax для дополнения запросов ajax к вашему интерфейсу REST.

Это то, что вы ищете?

Другие вопросы по тегам