I am currently using Django rest framework and trying to implement a Token Authentication system. Currently, my settings.py looks like this:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication'
]
}
and rest_framework.authtoken is in installed_apps.
My urls.py looks like this:
urlpatterns = [
...
url('^v1/users/$', views.users_view),
...
]
My views.py looks like this:
#authentication_classes((TokenAuthentication,))
#api_view(['PUT', 'POST'])
def users_view(request):
...
I'm working in postman to test the API and regardless of whether I put the token in the authorization field, the API works as intended. What do I need to change for the token authentication to work as intended?
Update:
Reqbin is also giving me the same functionality so I don't think it's a problem with postman.
You need to add permission class as well.
#authentication_classes((TokenAuthentication,))
#permission_classes((IsAuthenticated,))
#api_view(['PUT', 'POST'])
def users_view(request):
...
It appears there is a bug in Django that won't allow some authentications to work with function based views. I can confirm it doesn't work for TokenAuthentication and needed to use class based views.
Related
Risking this question to be too generic...
What would be the advised use case types to test in a regular implementation of a REST API using the djangorestframework plugin?
I don't know that I understand your question very well,
Code without tests is broken as designed.
So each part of an application need test. you should test the functionality of each API with unit-test, and fortunately, Django rest framework has tools for this action
http://www.django-rest-framework.org/api-guide/testing/
from django.urls import include, path, reverse
from rest_framework.test import APITestCase, URLPatternsTestCase
class AccountTests(APITestCase, URLPatternsTestCase):
urlpatterns = [
path('api/', include('api.urls')),
]
def test_create_account(self):
"""
Ensure we can create a new account object.
"""
url = reverse('account-list')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
I am using Django 1.11 and Django rest framework 3.6.2
I created a custom authentication backend:
MyAuthBackend(rest_framework.authentication.BasicAuthentication):
# ...
and added it to the settings.py file:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES' : ('path.to.MyAuthBackend',)
}
I also tried to extend SessionAuthentication without success
My issue is that users are trying to log in via the browsable api and it looks like the authentication backend that the browsable api is using is not the default one.
Where can I change that? I have to use my own auth backend in the browsable api,
Thank you.
I don't think it's possible to use BasicAuthentication in the browseable api (without changing a whole bunch of its internals).
Consider keeping the SessionAuthentication alongside your new one, you can use basic authentication in your app and session authentication in the browsable api:
'DEFAULT_AUTHENTICATION_CLASSES': (
'path.to.MyAuthBackend',
'rest_framework.authentication.SessionAuthentication',
),
I am building an API which has basic authentication enabled. When I'm trying to add an instance to the database (on a viewset which has the AllowAny setting) using the browsable api it. This works when I am not logged. However when I'm not logged in it gives me an error:
HTTP 400 Bad Request
Content-Type: application/json
Vary: Accept
Allow: POST, OPTIONS
{
"product": [
"This field is required."
],
"buyername": [
"This field is required."
],
"buyeremail": [
"This field is required."
]
}
This is the viewset:
class TicketBuyerViewSet(mixins.CreateModelMixin,
viewsets.GenericViewSet):
queryset = Ticket.objects.all()
serializer_class = TicketSerializer
permission_classes = (IsOwnerOrReadOnly,permissions.AllowAny)
def perform_create(self, serializer):
serializer.save(isPayed=False,checkedIn=False,isRefunded=False,checkedInDate=None,paymentID="",paymentDate=None)
And this is my urls.py file:
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('events.urls')),
url(r'^docs/', include('rest_framework_swagger.urls')),
]
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
I have been having this problem only recently. I made the snippets app from the django docs which worked perfectly for about a week. However, since a couple day I have the same problem with this api as with my 'own' api. I have tried chrome and firefox as well.
Edit: While I get why the http error codes may be confusing opposed to my question I do highly suspect the error lies in the django-rest authentication because when I log out and I fill in the EXACT same data it DOES work. Here are the response error codes for the PUT request when I'm logged in and logged out respectively:
[03/Nov/2015 20:38:44] "POST /ticketsbuyer/ HTTP/1.1" 400 10513
[03/Nov/2015 20:39:24] "POST /ticketsbuyer/ HTTP/1.1" 201 4543
Edit 2: I downloaded the exact source code from the django-rest-framework-tutorial github. I created a superuser and the EXACT same thing happened, for some reason django rest browsable api or my browser is not sending the post data correctly.
Edit 3 For some reason it worked for me to downgrade to version 3.2.5 of the rest-framework. I'm not the only one with this problem: Django Rest Framework - Browsable API Form always returns 400 bad request
There's an opened bug about this: https://github.com/tomchristie/django-rest-framework/issues/3588
However, I wasn't able to reproduce yet. Help is welcomed to understand what's going on.
Edit: thanks, it seems indeed that the authentication is the key in this bug.
Edit: upgrading to 3.3.1 should fix the issue.
HTTP400 is not generally an authentication error. Typically it is a data error. The message it is sending back says that you did not send the required fields so check the data you are sending and make sure it is meeting all the required fields. If it was an authentication issue it would be returning a HTTP401
Currently I've extended the standard Django user class by linking it to a profile class. The profile model is partially used for account activation through email, and includes an account_activated boolean. I'd like to require that accounts be activated in order to login in any way, including using the login button that is added to the django rest framework browsable api by adding
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
from the tutorial here http://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/
to the project urls. Is there any way to do this?
I think this is a classical example where permissions work fine. What you need to do:
Create a permission class that will check for a user if her account
is activated. For more see drf documentation;
Add your new permission class to the set of default permissions in settings.py in drf settings:
settings.py
REST_FRAMEWORK = {
...,
'DEFAULT_PERMISSION_CLASSES': [
...,
'your.permission.class',
...,
],
...
}
I'm learning how do RESTfull web services using django_rest_framework. I have this in urls.py :
urlpatterns = patterns('',
url(r'^tests/', 'Web_Services.views.test'),
)
ans I have a test function in views.py :
#api_view(['GET', 'POST'])
def test(request, format=None):
return Response({'Test OK!'})
my problem is that what when I add /?format=xml or anything other than json to the url I get 404 error. Another question : I get Assignment to reserved built-in symbol: format warning. I know what's it means but it's not me who decided to call it format. What I must do to resolve this problem.
Try adding this to your settings.py:
REST_FRAMEWORK = {
...your other DRF settings
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.XMLRenderer',
'rest_framework.renderers.JSONRenderer',
)
}
See the relevant DRF documentation here:
http://www.django-rest-framework.org/api-guide/renderers#setting-the-renderers
A couple other things I can think...perhaps it's related to your url pattern not having $, can you try:
url(r'^tests/$', 'Web_Services.views.test'),
Also, make sure your data is valid JSON, try returning ["TestOK!]. Note the double-quotes.
Do you have any other urlpatterns defined in the project?