Django, TastyPie, Authentication, and custom middleware headache
Asked Answered
A

1

1

I have a Django web application which requires authentication across the whole site. I've accomplished that with custom middleware which basically test if request.user.is_anonymous and, if they are, redirects them to the login page. It looks like this:

from django.contrib.auth.views import login
from django.contrib.auth import authenticate
from django.http import HttpResponseRedirect, HttpResponse
from django.utils import simplejson
from django.core import serializers

class SiteLogin:
    "This middleware requires a login for every view"
    def process_request(self, request):
        if request.path != '/accounts/login/' and request.user.is_anonymous():
            if request.POST:
                return login(request)
            else:
                return HttpResponseRedirect('/accounts/login/?next=%s' % request.path)

Now I'm making an iOS app which, for now, will just do GET requests off the Django server. I am trying to use TastyPie to do this but I can't get the the authentication working. I am using ApiKeyAuthentication and, I believe, have set it up properly. However, it just redirects me to the login page. I'm wondering if I need to edit this middleware to handle TastyPie requests, but I thought TastyPie could to auth for me...

I feel like my situation is very similar to this question, but I wonder if my custom middleware is getting in the way.

Here's my api.py:

from django.contrib.auth.models import User
from django.db import models
from tastypie.resources import ModelResource
from cpm.systems.models import System
from cpm.products.models import Product
from tastypie.models import create_api_key
from tastypie.authentication import ApiKeyAuthentication
from tastypie.authorization import DjangoAuthorization, Authorization

models.signals.post_save.connect(create_api_key, sender=User)



class SystemResource(ModelResource):
  class Meta:   
    queryset = System.objects.all()
    resource_name = 'system'
    authentication = ApiKeyAuthentication()
    authorization = DjangoAuthorization()


class ProductResource(ModelResource):
  class Meta:       
    queryset = Product.objects.all()
    resource_name = 'product'
    authentication = ApiKeyAuthentication()
    authorization = DjangoAuthorization()

And a portion of my urls.py:

from cpm.ios.api import SystemResource, ProductResource
from tastypie.api import Api

v1_api = Api(api_name='v1')
v1_api.register(SystemResource())
v1_api.register(ProductResource())

admin.autodiscover()

urlpatterns = patterns('',

    # iOS TastyPie related:
    (r'^ios/', include(v1_api.urls)),
    # .... more urls....

The URL I try to navigate to is:

http://192.168.1.130:8080/ios/v1/system/C0156/?username=garfonzo&api_key=12345?format=json

But I'm just redirected to my login page. I've followed the tutorial to a tee, created an api key on my Admin panel, and added WSGIPassAuthorization On to my apache config.

Any ideas?

EDIT I just removed that middleware altogether and now all I receive are 401 AUTHENTICATION errors...

EDIT 2 I should point out that if I remove the ?format=json then I get a response of: Sorry, not implemented yet. Please append "?format=json" to your URL.. So it's like it does authenticate, but then fails because I'm not specifying the format.

So my URL looks like this: http://192.168.1.130:8080/ios/v1/system/C0156/?username=garfonzo&api_key=12345 but as soon as I add the ?format=JSON then it goes to a 401 error.

Adiathermancy answered 29/8, 2014 at 17:12 Comment(2)
Re: format=JSON. When you append a pair to the querystring, ? is used only in the beginning. The rest of the pairs are separated by &. So, your querystring/url should look like - 192.168.1.130:8080/ios/v1/system/C0156/…Idona
@Idona - WOW - that worked! OK, so I'm a step closer. I can now actually authenticate properly so long as I don't use my custom middleware. So this is good progress. So the second half of this question is still there -- my middleware.py (shown in question) is now getting in the way. Have I set it up wrong? Shouldn't TastyPie be able to navigate/authenticate for me and thereby bypass my middleware?Adiathermancy
I
2

TastyPie requests go through the same stack of middlewares as any typical django request. So, it's definitely your middleware. You have to rethink it, or just drop to the basics and use @login_required.

The api key doesn't work after you disabled the middleware because your URL is malformed. You can't use a ? in a querystring after you used it once. Try this url:

http://192.168.1.130:8080/ios/v1/system/C0156/?username=garfonzo&api_key=12345&format=JSON
Idona answered 29/8, 2014 at 22:18 Comment(3)
Yup -- this was my problem, malformed URL. So, I have a LOT of views (it's a big corporate site). Does that mean I need to decorate them all with @login_required just to allow tastypie to do it's thing?Adiathermancy
Well, you can go lots of ways: If you use class based views, you can add a mixin that will take care of it. You can add the middleware but check if the request is going to tastypie views...Idona
Alright, cool, something to think about. At least I know what the root cause of my problem is and can at least determine a good approach to resolve it. Thanks for your help! I've been pulling my hair out for the past 48 hours!Adiathermancy

© 2022 - 2024 — McMap. All rights reserved.