I've been reading a lot on django-piston and using to to make an API for an app I'm development, but I'm getting hung up on the client side of the world. I've written the handlers and uri mappings, and I can return JSON or XML to my heart's content. Where I'm getting stuck is what to do with that now.
My ideal endgame is to have an iPhone and Android client consume and return data, but I don't know the right way to handle authentication. The easiest way I can figure is saving the username and password on the device and tagging each request with it, ultimately using Basic Authentication, but that wreaks of wrong. I've looked in to piston's support for OAuth and gotten it working with the help of this tutorial, but that doesn't feel like the right answer, either. Ultimately, I'd really like to have a simple prompt on the device for username and password, those will be sent up to Django via Piston and REST, and an API key will return down. The device will store that key and tag all subsequent requests with it. That feels like the right way, but I can't figure out how to do it. Can any one point me in the right direction?
You can write your own authentication module. Here's an example:
class ApiKeyAuthentication(object):
def is_authenticated(self, request):
auth_string = request.META.get("HTTP_AUTHORIZATION")
if not auth_string:
return False
key = get_object_or_None(ApiKey, key=auth_string)
if not key:
request.user = AnonymousUser()
return False
request.user = key.user
return True
def challenge(self):
resp = HttpResponse("Authorization Required")
resp['WWW-Authenticate'] = "Key Based Authentication"
resp.status_code = 401
return resp
You'll need a model to store a mapping of API keys to Users:
class ApiKey(models.Model):
user = models.ForeignKey(User, related_name='keys')
key = models.CharField(max_length=KEY_SIZE)
You'll need some method to generate the actual keys. Something like this will work (say, in the ApiKey model's save
method:
key = User.objects.make_random_password(length=KEY_SIZE)
while ApiKey.objects.filter(key__exact=key).count():
key = User.objects.make_random_password(length=KEY_SIZE)
Lastly, hook up your new authentication backend:
# urls.py
key_auth = ApiKeyAuthentication()
def ProtectedResource(handler):
return resource.Resource(handler=handler, authentication=key_auth)
your_handler = ProtectedResource(YourHandler)
As for swapping username / password for an API key, just write a handler that uses BasicAuthentication to create and return new ApiKey (for request.user).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With