Ajax Django Login/Authentication without re-direct

2019-05-19 10:26发布

问题:

I am trying to have an authentication set-up similar to that of StackOverflow, where the normal browsing is never affected unless there are some privileged actions which requires authentication (Do not bother users until then).

It should be as "Log In" if not logged in or "UserName" if logged in.

The relevant part of base.html (from fallr.net) (extended by index.html) looks like :

            <script type="text/javascript">
            //<![CDATA[

            $(document).ready(function(){

            var methods = {

            forms : function(){
            var login = function(){
            var user = $(this).children('form').children('input[type="text"]').val();
            var pass = $(this).children('form').children('input[type="password"]').val();
            var dataString = '&username=' + $('input[name=username]').val() + '&password=' + $('input[name=password]').val();
            if(user.length < 1 || pass.length < 1){
            alert('Invalid!\nPlease fill all required forms');
            } else {
            alert('username: '+user+'\npassword: '+pass);
            $.ajax({
            type: "POST",
            url: "/login",
            dataType: "html",
            data: {
            username : user,
            password : pass,
            csrfmiddlewaretoken : '{{ csrf_token }}'
            },
            success: function(json){alert (json.server_response);},
            error: function(xhr,errmsg,err) { alert(xhr.status + ": " + xhr.responseText); }
            });
            $.fallr('hide');
            return false;
            }
            }

            $.fallr('show', {
            icon        : 'secure',
            width       : '320px',
            content     : '<h4>Sign in</h4>'
            + '<form>'
            +     '<input name="username" placeholder="username" type="text"/'+'>'
            +     '<input name="password" placeholder="password" type="password"/'+'>'
            + '</form>',
            buttons : {
            button1 : {text: 'Submit', onclick: login},
            button4 : {text: 'Cancel'}
            }
            });
            }
            };

            //button trigger
            $('a[href^="#fallr-"]').click(function(){
            var id = $(this).attr('href').substring(7);
            methods[id].apply(this,[this]);
            return false;
            });

            // syntax highlighter
            hljs.tabReplace = '    ';
            hljs.initHighlightingOnLoad();
            });

            //]]>
            </script>

The urls.py looks like :

            from django.conf.urls import patterns, include, url
            #from triplanner.views import *


            # Uncomment the next two lines to enable the admin:
            # from django.contrib import admin
            # admin.autodiscover()

            urlpatterns = patterns('',
            url(r'^$', main_page),
            url(r'^login$',ajax_login),                 
            url(r'^login/$','django.contrib.auth.views.login'),
            url(r'^logout/$', logout_page),

            # our application page
            url(r'^account/',include('tripapp.urls')),              
            )

Also, '^login/$' is the previous implementation for learning which I want to replace with Ajax login.

And my views.py:

            # -*- coding: utf-8 -*-
            from django.contrib.auth import logout
            from django.http import HttpResponseRedirect
            from django.shortcuts import render_to_response
            from django.contrib.auth import authenticate, login
            #from django.http import HttpResponse
            from django.template import RequestContext
            #from django.utils import simplejson



            def main_page(request):
            return render_to_response('index.html', context_instance=RequestContext(request))


            def logout_page(request):
            """
            Log users out and redirect them to the main page
            """
            logout(request)
            return HttpResponseRedirect('/')


            def ajax_login(request):
            """  
            This view logs a user in using the POST data.
            """

            if request.method == 'POST':
            print request.POST['username']
            username = request.POST['username']
            password = request.POST['password']
            print username
            print password
            user = authenticate(username=username, password=password)
            if (not user is None) and (user.is_active):
            login(request, user)
            response_dict = {}
            response_dict.update({'server_response': username})
            #return HttpResponse(simplejson.dumps(response_dict),mimetype='applicaion/javascript')
            return render_to_response('index.html',{'username' : user}, context_instance=RequestContext(request))
            # Set Session Expiry to 0 if user clicks "Remember Me"
            #if not request.POST.get('rem', None):
            #   request.session.set_expiry(0)
            #data = username
            else:
            return render_to_response('index.html', context_instance=RequestContext(request))

I am getting a 403 Error like "[20/Aug/2013 00:29:20] "POST / HTTP/1.1" 403 2294"

UPDATE NUMBER 1:

With the changed urls.py, views.py and javascript I am able to get a 200 response, but it gives alert window saying undefined and alerting me "Prevent this page from creatng dialog boxes"

回答1:

The approach I use is to have a Tastypie api layer and require authentication for the APIs. If the API call fails because of authentication, the client can request the user to log-in via the ajax login method.

You can log-in a user via ajax using this gist



回答2:

So, it looks like your current problem is with this: alert (json.server_response);. You may want to look into changing your $.ajax dataType parameter to json.

To quote the docs:

The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string). The available types (and the result passed as the first argument to your success callback) are:...

"html": Returns HTML as plain text; included script tags are evaluated when inserted in the DOM.

"json": Evaluates the response as JSON and returns a JavaScript object. The JSON data is parsed in a strict manner; any malformed JSON is rejected and a parse error is thrown. As of jQuery 1.9, an empty response is also rejected; the server should return a response of null or {} instead. (See json.org for more information on proper JSON formatting.)