Django Remote Authentication without redirecting

自古美人都是妖i 提交于 2019-11-30 07:33:04

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?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!