In my application I need to authenticate users via my REST API. So I have a form with user/pass fields, and after submitting it, I'd like to proceed directly to the 'next' page. So apparently I need to submit my form via AJAX, as I don't want to be redirected to the API page. But how then the RemoteUserMiddleware
will know that my user should be authenticated if the request will be processed by javascript ?
问题:
回答1:
To my understanding of the system architecture you have currently looks something like the following:
-------------- ------------------- -------------------
| client web | ----------> | REST API | ----> | db / persistent |
| browser | <---------- | pylons / nodejs | <---- | storage |
-------------- ------------------- -------------------
^ | ^ |
| | | |
| | | v
| | ----------------- -------------------
| ------------------> | django | ------> | db / persistent |
--------------------- | | <------ | storage |
----------------- -------------------
Your question relates to how to log in and out users on the django app when the authentication is carried out in the REST API webapp.
I'm not sure that the RemoteUserMiddleware
is what you are looking for, it is designed to allow authentication by an Apache webserver layer when django is run using wsgi on that same server. The name relates to the REMOTE_USER
unix system variable which is an old school authentication method in apache.
It seems unwise to allow the client to be an intermediary in the authentication chain between django and your REST API, this would seem to be inherently insecure. Instead, django can call the REST API directly to authenticate users and then create a corresponding django.contrib.auth.models.User
object to store locally this is carried out in a custom authentication backend, see here.
Something like:
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
This uses the requests library to call the REST API with a synchronous http request to log the user in and then creates a local instance of the User object, if one doesn't already exist. There are more complicated protocols for remote authentication, if required, http://oauth.net/2/ is an example.
This backend should be specified in the settings.py
file
AUTHENTICATION_BACKENDS = ('my.classy.django.app.RestBackend')
Then your django app can use the authenticate
and login
functions in it's views, either using http or json, more info here.
Django will set the request.user
to be an object of class AnonymousUser
until the user is logged in, docs here. This allows you to differentiate between these users in your views without using redirects:
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")
or if you wanted a 'user profile' box to appear on the page, ala stackoverflow:
# 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")
If, instead, you are using templates and not ajax to render your page then this logic could be passed to the template, with areas appearing when a user logs in, without having to use redirects:
{% 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 %}
This relies on the user object being based into the template by the view, and would require the javascript to hook up the authenticate the backend.
It is also possible to use render_to_string()
to render a context with a template, and return this to an ajax request instead of json. Thus allowing html to be rendered on the server and returned to the client without having to reload the page in the client.
In this manner it is possible to get django to render some templates and use some ajax responses to complement ajax requests to your REST interface.
Is this something like what you are looking for?