Django Remote Authentication without redirecting

后端 未结 1 876
一向
一向 2020-12-30 16:18

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\

相关标签:
1条回答
  • 2020-12-30 16:26

    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?

    0 讨论(0)
提交回复
热议问题