7

I'm working with DRF and came across this issue. I have a third-party view which I'm importing in my urls.py file like this :

from some_package import some_view

urlpatterns = [
    path('view/',some_view)
]

but the issue I'm facing is since I have enabled default permission classes in my settings.py like this:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
               'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES':(
                'rest_framework.permissions.IsAuthenticated',
    ),

}

now when I call that view using the url , it gives me authentication error as I'm not providing token .Is there a way I can bypass authentication error without having to make changes in view directly,I know that we can remove permission for that particular view , but for that I'll have to make changes to that some_view function code. But I don't want to do that,let's say we don't have access to that function we can only pass data and receive response. How can I bypass authentication without having to change that functions code . I tried searching but couldn't find what I'm looking for.

I was assuming that there might be someway we can do that from urls.py like specifying any parameter or something like that which make that particular view to bypass authentication without having to change functions code.

somthing like this :

from some_package import some_view

    urlpatterns = [
        path('view/',some_view,"some_parameter") #passing someparameter from here or something like that
    ]

Is it possible what I'm looking for ? Thanks in advance :)

Bedilbek
  • 849
  • 7
  • 17
Shubham Devgan
  • 609
  • 6
  • 18
  • I'm not aware of any way to do this. Your best bet is to wrap the view (i.e. write your own) and set the `authentication_classes`. Would that work for you? – yvesonline Mar 13 '20 at 07:44
  • 1
    You could also remove the `DEFAULT_AUTHENTICATION_CLASSES` & `DEFAULT_PERMISSION_CLASSES` and move this into your own parent class for authentication and authorization and then inherit from this in your views. Then your third-party view wouldn't default to what you provided in `settings.py` as you haven't provided anything. – yvesonline Mar 13 '20 at 07:47
  • yes I can do that but that would result in making more changes,instead of doing what you are suggesting it would be better to override that function and specify `authentication_classes` for overridden function and then call original function from that overridden function . @yvesonline – Shubham Devgan Mar 13 '20 at 08:31
  • That was what I meant with my first comment. Quite honestly if it's just one view you're importing I think this is the way to go. – yvesonline Mar 13 '20 at 08:48
  • I already tried this override way. It's worked fine for me. It's good idea to do this way. I did it long back. – Razia Khan Mar 13 '20 at 10:38

3 Answers3

6

So, the most appropriate way for third-party views is to use decorators by defining them inside your urls.py:

Case 1

I assume that some_view is a class inherited from rest_framework.views.APIView:

urls.py

from django.urls import path
from rest_framework.decorators import permission_classes, authentication_classes
from rest_framework.permissions import AllowAny

from some_package import some_view

urlpatterns = [
    path('', authentication_classes([])(permission_classes([AllowAny])(some_view)).as_view())
]

Case 2

I assume that some_view is a simple Django view function and you need to define it for GET method:

urls.py

from django.urls import path
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import AllowAny

from some_package import some_view

urlpatterns = [
    path('', api_view(['GET'])(authentication_classes([])(permission_classes([AllowAny])(some_view))))
]

Case 3

I assume that some_view is an api_view decorated DRF view function. This is the hardest and most probably the most impossible part because you have to undecorate the previous api_view decorator. If view function is decorated with api_view, then it is already converted into Django view function so neither permision_classes nor authentication_classes can be appended to class:

Bedilbek
  • 849
  • 7
  • 17
0

You can override the default authentication class to skip auth for specific urls.

For example:

class CustomIsAuthenticated(IsAuthenticated):

    def has_permission(self, request, view):
        # make a list of public urls
        if request.path in PUBLIC_URLS:
            return True
        return super().has_permission(request, view)

You have to create a list of PUBLIC_URLS which bypass authentication.

Now use this class in the DEFAULT_PERMISSION_CLASSES in rest framework settings. And remove the default IsAuthenticated class.

Although I recommend the decorators approach. check docs: https://www.django-rest-framework.org/api-guide/permissions/#allowany

Decorators approach is more verbose and by looking at the function you can make out if it is public or not.

zaphod100.10
  • 3,331
  • 24
  • 38
0

@Bedilbek's answer worked for me, but if you'd prefer to use different syntax and define the permission_classes and authentication_classes inside your view instead of urls.py, you can do the following:

from rest_framework import permissions
from rest_framework.views import APIView

class SomeView(APIView):
    permission_classes = [permissions.AllowAny]
    authentication_classes = []
Tonechas
  • 13,398
  • 16
  • 46
  • 80