How to use Rest Framework's default token authentication view? - python

I am trying to use DRF's builtin TokenAuthentication view, but I can't get it to work.
Here is the test:
import requests
import json
data = json.dumps({
'username': 'test-sandbox-root',
'password': 'password'
})
headers = {'Content-Type': 'application/json'}
r = requests.post('http://localhost:8000/api/auth', data=data, headers=headers)
>>> r.status_code
400
>>> r.text
'{"non_field_errors":["Unable to log in with provided credentials."]}'
But the user clearly exists:
>>> User.objects.get(username='test-sandbox-root', password='password')
<User: test-sandbox-root>
I've added the DEFAULT_AUTHENTICATION_CLASSES to my settings:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
}
And migrated the rest_framework.authtoken app:
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
...
]
And added optain_auth_token to my urls.py:
from rest_framework.authtoken import views
urlpatterns = [
path('/api/auth', views.obtain_auth_token),
]
What am I missing?

Related

how to send POST request with Postman using Django 4 ?? faced with : "detail": "CSRF Failed: CSRF token missing."

I faced with the problem. I write a simple test app. Now I want to use Postman to send a request. Everything is going ok if I send GET request I got all staff correctly. But if I try to send POST or PUT the error is "detail": "CSRF Failed: CSRF token missing." I logged in by admin. I took cookies from the session: sessionid and csrftoken but it did not work. In postman I tried copy CSRF token from headers. I used all this 3 tokens in fact. I tried usr each separately but all my attempts fold. What shall I do to send POST in Django 4 through Postman?????? I use here oauth with github
but the error appears in both cases: login with admin or oauth.
My code is below
settings.py
''''
"""
Django settings for books project.`enter code here`
Generated by 'django-admin startproject' using Django 4.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-ozz!^(_j!6gd5lc_f)&kyyo743l^g5r$sx!wg=9zd*)l7n'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'social_django',
'store',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'books.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
),
}
WSGI_APPLICATION = 'books.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'books_db',
'USER': 'books_user',
'PASSWORD': '',
'HOST': 'localhost',
'PORT': '',
}
}
AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2',
'django.contrib.auth.backends.ModelBackend',
)
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
SOCIAL_AUTH_JSONFIELD_ENABLED = True
SOCIAL_AUTH_GITHUB_KEY = 'e18b995bb43db2872f'
SOCIAL_AUTH_GITHUB_SECRET = '4cfb0b968b14a0f86491c5b3126550b72befe8'
CSRF_HEADER_NAME = 'LAPwVB8oVvcX4609bsaY3bi1SpiXBBpqZLnO84MBcsNtdjY7bboibRduwGDr'
urls.py
from django.contrib import admin
from django.urls import include
from django.urls import path
from rest_framework.routers import SimpleRouter
from store.views import auth
from store.views import BookViewSet
router = SimpleRouter()
router.register(r'book', BookViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('social_django.urls', namespace='social')),
path('auth/', auth)
]
urlpatterns += router.urls
models.py
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=7, decimal_places=2)
author_name = models.CharField(max_length=255)
def __str__(self):
return f'Id: {self.id}, name: {self.name}'
serializers.py
from rest_framework.serializers import ModelSerializer
from store.models import Book
class BooksSerializer(ModelSerializer):
class Meta:
model = Book
fields = '__all__'
views.py
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from django.shortcuts import render
from store.models import Book
from store.serializers import BooksSerializer
class BookViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BooksSerializer
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
permission_classes = [IsAuthenticated]
filter_fields = ['price']
search_fields = ['name', 'author_name']
ordering_fields = ['price', 'author_name']
def auth(request):
return render(request, 'oauth.html')
''''

DRF Token Authentication - not able to retrieve Token on Postman

I'm trying to retrieve a token for the user using the following request through Postman.
http://127.0.0.1:8000/api-token-auth/
JSON Body -
{
"username": "user1",
"password": "testpass"
}
The following is the error response -
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
I've checked the instructions provided in the official DRF Authentication document as well as various other question posts and implemented the following code.
settings.py
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
'allauth',
'allauth.account',
'allauth.socialaccount',
'rest_auth',
'rest_auth.registration',
....
]
AUTH_USER_MODEL = 'users.CustomUser'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
signals.py
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
urls.py
from django.contrib import admin
from django.urls import include, path, re_path
from django_registration.backends.one_step.views import RegistrationView
from rest_framework.authtoken import views as authtoken_views
urlpatterns= [
path('admin/', admin.site.urls),
path("accounts/",
include("django_registration.backends.one_step.urls")),
path("accounts/",
include("django.contrib.auth.urls")),
path("api-auth/",
include("rest_framework.urls")),
path("api-token-auth/", authtoken_views.obtain_auth_token, name="api-token-auth"),
path("api/rest-auth/",
include("rest_auth.urls")),
path("api/rest-auth/registration/",
include("rest_auth.registration.urls")),
]
Have I missed something?
Found the issue.
The issue was not with the implementation, rather it was with Postman. Postman interceptor had retrieved cookies from the browser and had stored the CSRF Token with it. This token was automatically added to the request headers and hence, django tried to authenticate this request from Session Authentication which naturally should fail.
The solution-
Open the Postman cookies and Delete the CSRF Token.
PS- A curl request can always help in verifying such issues

{ "detail": "Method \"GET\" not allowed." }

So the problem I have already mentioned. I am a beginner, I might be doing some silly mistakes. So humble request to you guys to address my mistake and help me to complete my project. Thanks you all in advance.
setting.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
}
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3600),
}
this is the setting.py file and here I mention the required file
view.py
class LoginViewSet(viewsets.ViewSet):
""" Check email and password and return auth token. """
serializer_class = AuthTokenSerializer
authentication_classes((SessionAuthentication, TokenAuthentication, BasicAuthentication))
permission_classes((IsAuthenticated,))
def create(self, request):
""" Use ObtainAuthToken APIView to validate and create a token. """
return ObtainAuthToken().post(request)
this is the view.py file.
urls.py
router.register('login', views.LoginViewSet, base_name="login")
urlpatterns = [
path('', include(router.urls)),
path('login/', ObtainAuthToken.as_view()),
path(r'api-token-auth/', obtain_jwt_token),
path(r'api-token-refresh/', refresh_jwt_token),
]
Error Message
error
you must define http_method_names in DRF and specify your method access in your api.
class IndexViewAPI(generics.GenericAPIView):
http_method_names = ['get', 'head']
# some statements

Token Authentication Not Working on Django Rest Framework

I have a Django application, which I am using DRF for my API with Session, and Token authentication. I have rest_framework, and rest_framework.authtoken in my installed apps. I have migrated my database and can create tokens for users in the Django Admin. I know all of this is working because I am accessing rest_framework.auth_token's obtain_auth_token view for returning a token when user data is submitted in a POST request, and receive one back. When I try to make a GET request to a view function in my app that has TokenAuthentication on its viewset, it keeps returning.
{"detail":"Authentication credentials were not provided."}
Settings File
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# My Apps
'rest_framework',
'rest_auth',
'rest_framework.authtoken',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
}
URLS
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken import views
from api.views.some_model import MyViewSet
urlpatterns = [
path('', include(router.urls)),
path('rest-auth/', include('rest_auth.urls')),
path('api-token-auth/', views.obtain_auth_token)
]
Viewset
from rest_framework.viewsets import ModelViewSet
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from some_app.models import SomeModel
from api.serializers.exams import SomeModelSerializer
class ExamViewSet(ModelViewSet):
permission_classes = (IsAuthenticated,)
authentication_classes = (TokenAuthentication, SessionAuthentication)
queryset = SomeModel.objects.all()
serializer_class = SomeModelSerializer
Python Script to Get Response
import requests
import json
data = {
"username": "myemail#gmail.com",
"password": "password124"
}
url = "http://localhost:8002/api/v1/api-token-auth/"
response = requests.post(url, data=data)
token = json.loads(response.text).get('token')
if token:
token = f"Token {token}"
headers = {"Authentication": token}
response = requests.get("http://localhost:8002/api/v1/model/", headers=headers)
print(response.text)
else:
print('No Key')
Header name should be Authorization not Authentication:
headers = {"Authorization": token}
response = requests.get("http://localhost:8002/api/v1/model/", headers=headers)
The token should be provided in the header like
-H "Authorization: Token 8fa36c01df3bb9ed31fc2329c53a9fe2cac72966"
Authorization:prefix YourToken
If you are using JWT authentication then your request header should look like
Authorization: JWT your-token-here
or
Authorization: Bearer your-token-here

Getting Permissions issue on sending the authenticated request to OAuth2.0 Django rest Framwork

I Have integrated the OAuth2.0 with django-rest-framework. When I send the authenticated request to my class based view I got this
{
"detail": "You do not have permission to perform this action."
}
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
views.py
from rest_framework import permissions
from oauth2_provider.contrib.rest_framework import TokenHasReadWriteScope
class LogoutView(APIView):
"""
This will help in logout of user.
"""
authentication_classes = ()
permission_classes = (permissions.IsAuthenticated, TokenHasReadWriteScope)
def get(self, request):
return Response({'s': 'd'})
urls.py
from django.urls import path, re_path
from accounts.views import SignUpView, LoginView, LogoutView
urlpatterns = [
path('signup/', SignUpView.as_view()),
path('login/', LoginView.as_view()),
path('logout/', LogoutView.as_view()),
]
And this is what my headers look like
Content-Type:application/json
Authorization:Bearer 4A7qGgmHpbEWlJn5w4wCwxJ9jWfTZ5
This is the access token that I generated.
Make sure you have the following in your settings.py
AUTHENTICATION_BACKENDS = (
'oauth2_provider.backends.OAuth2Backend',
'django.contrib.auth.backends.ModelBackend'
)
And:
OAUTH2_PROVIDER = {
'REFRESH_TOKEN_EXPIRE_SECONDS': 360000,
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'},
'ACCESS_TOKEN_EXPIRE_SECONDS': 1800
}
For debugging purposes:
Remove authentication_classes = () from view.py
Remove TokenHasReadWriteScope from view.py
If you want to make a logout endpoint, I would recommend using oauth2_views in your urls.py:
from oauth2_provider import views as oauth2_views
#.....
urlpatterns = [
#....
url(r'^logout/$', oauth2_views.RevokeTokenView.as_view()),
]

Categories

Resources