So you’ve developed a secure section of your site and now you need to create an AJAX view… but that view needs to be locked down as well.
The RequireSignIn mixin in the previous post returns an HttpResponseRedirect which won’t work in this situation.
First, let’s lock down the view to require the user to be logged in when making an AJAX request.
Here’s what the mixin looks like:
views/mixins/requiresigninajax.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.utils.decorators import method_decorator | |
from app.lib.ajax import login_required_ajax | |
class RequireSignInAjax(object): | |
@method_decorator(login_required_ajax()) | |
def dispatch(self, request, *args, **kwargs): | |
return super(RequireSignInAjax, self).dispatch(request, *args, **kwargs) |
You’ll notice that I’m making use of a method decorator – login_required_ajax. This decorator simply checks to see if the user is authenticated and if so, allows the request to continue. Otherwise it returns some json containing an error and the proper 401 http status which you could then use to ask the user to login.
Here’s the function:
lib/ajax.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from django.http import HttpResponse | |
from django.utils import timezone | |
from django.utils.dateformat import format | |
from django.conf import settings | |
def login_required_ajax(function=None): | |
# ensure the user is authenticated to access a certain ajax view | |
# otherwise return a json object notifying the user access is denied | |
def _decorator(view_func): | |
def _wrapped_view(request, *args, **kwargs): | |
if request.user.is_authenticated(): | |
return view_func(request, *args, **kwargs) | |
else: | |
now = format(timezone.now(), u'U') | |
# delete all existing kwargs | |
# as they cause HttpResponse to throw TypeError: __init__() got an unexpected keyword argument | |
kwargs = {'content_type': 'application/json'} | |
response = { | |
'status': '401', | |
'message': 'Unknown authentication scheme', | |
'timestamp': now, | |
'errorcode': settings.API_ERROR_AUTHENTICATION | |
} | |
return HttpResponse(status=401, content=json.dumps(response), **kwargs) | |
return _wrapped_view | |
if function is None: | |
return _decorator | |
else: | |
return _decorator(function) |
Ok, now we’ve made sure the user is logged in. Let’s add a simple mixin (pulled from the Django docs), to return some json:
mixins/jsonresponse.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from django.http import HttpResponse | |
class JSONResponseMixin(object): | |
# a mixin that can be used to render a JSON response | |
response_class = HttpResponse | |
def render_to_response(self, context, **response_kwargs): | |
# returns a JSON response, transforming 'context' to make the payload | |
response_kwargs['content_type'] = 'application/json' | |
return self.response_class(self.convert_context_to_json(context), **response_kwargs) | |
def convert_context_to_json(self, context): | |
# this would need to be a bit more complex if we're dealing with more complicated variables | |
return json.dumps(context) |
Finally, you can use these in your view like so…
views/myview.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.views.generic import View | |
from app.views.mixins.requiresigninajax import RequireSignInAjax | |
from app.views.mixins.jsonresponse import JSONResponseMixin | |
class MyView(RequireSignInAjax, JSONResponseMixin, View): | |
def get(self, request, *args, **kwargs): | |
return self.render_to_response(self.get_context_data(**kwargs)) |