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.
Это то, что вы ищете?