Django: Basic auth on only certain URL paths?

82 Views Asked by At

I would like to password-protect only certain parts of my Django app with basic-auth. I'd like to protect all URLs except anything under /api.

I'm trying to use the django-basicauth package to do this.

I've configured it as follows. My app has three parts:

/api
/candc
/places

In candc/localsettings.py I've added:

BASICAUTH_USERS = {
  "myuser": "mypass"
}

The candc/urls.py file looks like this:

urlpatterns = [
    path('', include('places.urls')),
    path('api/1.0/', include('api.urls')),
]

Then in my places/views.py file, I've added decorators to the URLs I want to protect, like this:

from basicauth.decorators import basic_auth_required

@basic_auth_required(
def index(request):
    template = loader.get_template('index.html')
    return HttpResponse(template.render({}, request))

However, my app is asking for basic-auth protect on URLs under /api as well. (In fact it's not even showing the dialog, just returning 403s for any requests.)

The api app is using django-rest-framework, which I suspect may somehow be related to this problem.

How can I configure this so URLs under /api are not password-protected, but everything else is?

3

There are 3 best solutions below

1
derdon On

As long as API urls are located in candc/urls.py they belong to the candc app. Therefore the settings for that app in candc/localsettings.py will apply for all API endpoints as well. So either you put your API stuff into a separate app (with separate urls.py) or you remove the BASICAUTH_USERS setting from localsettings.py and add @basic_auth_required to all views of the candc app.

0
Bill Huneke On

You are right, this is probably related to the fact that you are using Django Rest Framework (DRF). There is nothing you can do in the urls.py file to resolve this. You need to change the way you have configured your API. Luckily, this is pretty easy to do with DRF. You need to setup default authentication and permission classes so that permission is 'wide open'.

This easiest way to do this may depend on your version of DRF, but you should be able to get away with just adding this setting:

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [],
'DEFAULT_PERMISSION_CLASSES': [],
}
0
mahnoosh ramtin On

It would be a good idea to share your settings.py file. In any case, you can completely remove all related fields in the REST_FRAMEWORK variable and remove the DEFAULT_AUTHENTICATION_CLASSES field:

# in settings.py
REST_FRAMEWORK = {} 

Then you can specify the authentication class necessary before your view as such:

# in places/views.py
from rest_framework.authentication import BasicAuthentication

@authentication_classes([BasicAuthentication])
def index(request):
    ...