Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Key based access for the Django Rest Framework

Lets say the API endpoint to GET a list of users is this

/api_auth/user/

But I want to restrict access to this list only to people with an api_key

 /api_auth/user/?access_key=$omeRandomHash3252532

How do I implement such an access system using the Django Rest Framework?

Should I use Permissions to implement this?

like image 880
Sai Krishna Avatar asked Feb 02 '15 09:02

Sai Krishna


1 Answers

This is not supported out of the box for django-rest-framework, however it can easily be implemented:

If you take a look at http://www.django-rest-framework.org/api-guide/authentication/ you'll see an Example of a custom authentication method. Baased on that, you'll need to implement something like this:

from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

class APIKeyAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):
        api_key = request.GET.get('api_key')
        if not api_key:
            return None

        try:
            user = get_user_from_api_key(api_key)
        except User.DoesNotExist:
            raise exceptions.AuthenticationFailed('No user for API KEY')

        return (user, None)

The APIKeyAuthentication should be put on an authentication.py module and be configured with REST_FRAMEWORK setting on settings.py, like this

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'my_custom_package.authentication.APIKeyAuthentication',
    )
}

Now, what the above does is that it checks if the api_key parameter is present (if not it will return None to check if the request can be authenticated differently -- if you don't want to check any other authentication classes then just raise an exceptions.AuthenticationFailed exception like we do when we dont find the user below. Now, we need to implement a get_user_from_api_key function that will return a User instance from an API_KEY. If the user that is correlated with the passed api_key is found then it will be returned, if not an exceptions.AuthenticationFailedexception will be thrown.

Concerning the get_user_from_api_key function, its implementation depends on your requirements. For instance, if you want to create a new api key for each user, you should create an APIKey model that will have an api_key CharField and a ForeignKey to the User that has this api_key. The get_user_from_api_key function then will query the APIKey model to get the user with the provided api_key.

Update

If you want to use the django-rest-framework permissions instead of the authentication, you may create an APIKeyPermission class like this:


from rest_framework import permissions

class APIKeyPermission(permissions.BasePermission):
    def has_permission(self, request, view):
        api_key = request.GET.get('api_key')
        return check_permission(api_key, request)

Where the check_permission function will check if the api_key passed has permissions for that specific request. Please check the examples on http://www.django-rest-framework.org/api-guide/permissions/ for more info - you may instead choose to implement has_object_permission to implement object-level permissions instead of view-level permissions.

like image 173
Serafeim Avatar answered Sep 30 '22 07:09

Serafeim