Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django authentication and Ajax - URLs that require login

I want to add some Ajax-niceness to my Django-coded website.

In my Django code, I use the @login_required decorator from django.contrib.auth.decorators to mark which view requires authentication. The default behavior when a not authenticated user clicks it is to redirect him/her to login page, and then pass the target page.

What I saw on some sites, and really liked, is that when user clicks a link leading to a place restricted to logged-only users, instead of getting redirected to a login page, he/she gets a popup window (via JavaScript) asking him/her to log in or register. There's no redirection part, so no need for a user to use the "back" key if he/she decides he/she really doesn't like the website enough to waste the time registering.

So, the qestion is: how would you manage the task of automatically marking some links as "restricted" so JavaScript can handle their onclick event and display a "please log in" popup?

like image 877
kender Avatar asked Nov 23 '08 20:11

kender


People also ask

How do I authenticate username and password in Django?

from django. contrib. auth import authenticate user = authenticate(username='john', password='secret') if user is not None: if user. is_active: print "You provided a correct username and password!" else: print "Your account has been disabled!" else: print "Your username and password were incorrect."

How does Django integrate with Ajax?

Using Ajax in Django can be done by directly using an Ajax library like JQuery or others. Let's say you want to use JQuery, then you need to download and serve the library on your server through Apache or others. Then use it in your template, just like you might do while developing any Ajax-based application.

How do I authenticate using email and password in Django?

Email authentication for Django 3.x For using email/username and password for authentication instead of the default username and password authentication, we need to override two methods of ModelBackend class: authenticate() and get_user():


3 Answers

I am facing the same issue, and, like you, I would like a simple decorator to wrap around a Django ajax view in order to handle authentication in the same way that I have other views. One approach that seems promising to me is to use such a decorator in conjunction with JavaScript that looks for a certain value in the response.

Here is first revised draft of the decorator:

from functools import wraps  def ajax_login_required(view_func):     @wraps(view_func)     def wrapper(request, *args, **kwargs):         if request.user.is_authenticated():             return view_func(request, *args, **kwargs)         json = simplejson.dumps({ 'not_authenticated': True })         return HttpResponse(json, mimetype='application/json')     return wrapper 

Here is the view:

@ajax_login_required def ajax_update_module(request, module_slug, action):     # Etc ...     return HttpResponse(json, mimetype='application/json') 

And here is the JavaScript (jQuery):

$.post('/restricted-url/', data, function(json) {     if (json.not_authenticated) {         alert('Not authorized.');  // Or something in a message DIV         return;     }     // Etc ... }); 

EDIT: I've attempted to use functools.wraps, as suggested. I have not actually used this decorator in working code, so beware of possible bugs.

like image 183
Eric Walker Avatar answered Oct 06 '22 00:10

Eric Walker


Sounds like a page template possibility.

  1. You could pass a LINK_VIA (or something) that you provide as onClick="return popup(this, 'arg')" or None. Each link would be <A HREF="link" {{LINK_VIA}}>some text</a>.

    • For anonymous sessions, LINK_VIA has a value.
    • For logged in sessions, LINK_VIA is None
  2. You could use an {% if %} statement around your <A HREF=...> tags. This seems wordy.

  3. You could write your own custom tag with for {% link_via %}. I'm not familiar enough with this, but you can provide the link and text as strings and your tag can generate one of two kinds of links.

like image 32
S.Lott Avatar answered Oct 05 '22 22:10

S.Lott


I would agree with S.Lott

Make a check in the template, if the user is logged in, just put the link as usual, if not, put something like

<a href="{{link}}" onclick="return login_popup()"> 

where login_popup would return false if the user says cancel.

This could be probably be done much easier in Jinja2 through its macros.

If the template doesn't know which urls require the user to login, you probably need to re-consider your design.

If you must, I guess you can do the same thing that the django url dispatcher does to discover the view function.
see: django.core.urlresolvers

once you've grabbed the view function you can check if it's decorated with @login_required.

This would be done in a custom tag probably.
If you use Jinja2, you won't need the tag, just implement the function and expose it to the Environment, it's simple but you'll have to do a bit of reading on the API of Jinja2)

like image 28
hasen Avatar answered Oct 06 '22 00:10

hasen