I am developing an api in Django Rest Framework, which at the moment only registers new users, but I have a problem and that is that now I am adding a bit of security, which is being controlled by means of tokens, but at the time of entering the token of an authenticated user for the creation of users generates an error of The authentication credentials were not provided, but I send the token as follows:
This is plugin rest client visual studio code
My authentication:
### Login user
POST http://localhost:8000/auth-token/
Content-Type: application/json
{
"username": "hamel",
"password": "contraseña"
}
This return a token b6773c67ecb940ae4fb7c9d49466a01fd46f5eb4
My register of user:
### Create User
POST http://localhost:8000/api/v1/users
Authorization: Token b6773c67ecb940ae4fb7c9d49466a01fd46f5eb4
Content-Type: application/json
{
"first_name": "Carlos",
"last_name": "Carlos",
"username": "carlos",
"email": "correo#rgrgr.com",
"password": "contraseña",
"password2": "contraseña"
}
My setting.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
This my views.py:
class CreateUser(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request, format=None):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
This is my INSTALLED_APPS:
INSTALLED_APPS = [
'users',
'profiles',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
]
This is my MIDDLEWARE:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
This my urls main:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from users.views import CustomToken
urlpatterns = [
path('auth-token/', CustomToken.as_view()),
path('api/v1/', include('users.urls')),
path('admin/', admin.site.urls),
] + static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT,
)
This my urls app users:
from django.urls import path
from . import views
urlpatterns = [
path('users', views.CreateUser.as_view()),
]
Related
views.py
class StorageView(viewsets.ModelViewSet):
serializer_class = StorageSerializer
def get_queryset(self):
if self.request.user.is_authenticated:
user = self.request.user
queryset = Storage.objects.filter(username=user.username)
return queryset
else:
print(self.request.user)
return []
urls.py
from django.urls import path, include
from django.urls import re_path as url
urlpatterns = [
path('auth/', include('rest_auth.urls')),
path('auth/register/', include('rest_auth.registration.urls'))
]
settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# CORS
'corsheaders',
# REST
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_auth.registration',
'django.contrib.sites',
# App
'backend'
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'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',
]
SITE_ID = 1
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_SESSION_REMEMBER = True
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_UNIQUE_EMAIL = True
REST_FRAMEWORK = {
'DATETIME_FORMAT': "%m/%d/%Y %I:%M%P",
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
}
I logging in via form or api, but is_authenticated method don't see me
Login via api
postman screenshot
Condition in get_queryset() function in views.py always evaluates to false, even if i logged in it keeps printing "AnonymousUser", why? How to check if user is logged in, in my case?
Provide
permission_classes = [IsAuthenticated]
in your views.
and pass
Authorization token with every request
axios
.get(
`http://localhost:8000/anything`,
{
headers: {
Authorization: `Token ${token}`,
},
}
)
I have a Django REST Framework project and I added
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
]
}
to settings.py and I expect BasicAuthentication is applied to all pages as default but still it does not require any authentication to display the content. that is weird. Do I have to do something I did not do?
urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('student/', include('blogapp.urls')),
path('api/', include('api.urls')),
path('api-auth/', include('rest_framework.urls')),
]
setting.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'blogapp',
]
blog_app/urls:
urlpatterns = [
path('', StudentView.as_view()),
]
views.py:
class StudentView(generics.ListCreateAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
UPDATE 1:
Also per-view authentications not work!
UPDATE 2:
This is my project source code.
Authentication is not the same as permission. You'll also need to add a default permission class if you require all users to be authenticated (using one of the authentication methods you wish to use):
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
Also, make sure you're testing the right view (/api/list/). Your project (as you linked) has two StudentViews, one of which is a DRF view, the other (/student/) isn't. The latter will not be aware of DRF configuration.
I am trying to perform a PUT request in Vue view from DRF API backend. Though POST and GET requests are working properly in Vue(frontend) but for PUT request it's returning INTERNAL SERVER ERROR 500
Here is what I have done.
settings.py
INSTALLED_APPS = [
...,
'rest_framework',
'corsheaders',
'articles'
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'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',
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
}
CORS_ALLOWED_ORIGINS = [
"http://localhost:8080"
]
views.py
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
view.vue
updateArticle(article) {
axios
.put('http://127.0.0.1:8000/api/' + article.id,
this.article
)
.then(response => {
this.fetchArticle();
this.editArticle = null;
return response;
})
.catch(error => console.log(error))
}
urls.py
from .views import ArticleViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', ArticleViewSet, basename='articles')
urlpatterns = router.urls
You called this URL via PUT, but the URL doesn't end in a slash and Django can't redirect to the slash URL while maintaining PUT data.
Just add '/' at the end of the URL
In your view.vue
updateArticle(article) {
axios
.put('http://127.0.0.1:8000/api/' + article.id + '/',
this.article
)
.then(response => {
this.fetchArticle();
this.editArticle = null;
return response;
})
.catch(error => console.log(error))
}
When trying to create a django(2) rest framework api, I keep getting this error.
Forbidden (CSRF token missing or incorrect.): /login/
After doing some research the problem might be with sessions authentication which I don't really need since I will be replying on token based auth. When I try to remove some of the session auth from my settings I end up getting this.
AssertionError: The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.sessions.middleware.SessionMiddleware' before 'django.contrib.auth.middleware.AuthenticationMiddleware'.
Settings.py snippet
INSTALLED_APPS = [
# API (v1)
'apiV1.v1.accounts.apps.AccountsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Requirements
'corsheaders',
'rest_framework',
'rest_framework.authtoken',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'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 = 'apiV1.urls'
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.TokenAuthentication',
# 'rest_framework.authentication.SessionAuthentication',
),
}
Views.py
from django.contrib.auth import authenticate
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from apiV1.v1.accounts.models.user import User
from apiV1.v1.accounts.serializers.user import UserSerializerLogin
# login
class LoginView(APIView):
authentication_classes = ()
permission_classes = ()
#staticmethod
def post(request):
"""
Get user data and API token
"""
user = get_object_or_404(User, email=request.data.get('email'))
user = authenticate(username=user.email, password=request.data.get('password'))
if user:
serializer = UserSerializerLogin(user)
return Response(serializer.data)
return Response(status=status.HTTP_400_BAD_REQUEST)
If you don't need session for authentication you have to use token authentication.
Here is the example of view
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.response import Response
class Login(ObtainAuthToken):
def post(self, request, *args, **kwargs):
"""
---
serializer: AuthTokenSerializer
"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'pk': user.pk,
'first_name': user.first_name,
'last_name': user.last_name,
})
Or you can use JWT authentication.
Here are some helpful links for you.
http://www.django-rest-framework.org/api-guide/authentication/
http://getblimp.github.io/django-rest-framework-jwt/
I am using Djando rest_auth.registration.
My corresponding entry in urls.py is
url(r'^rest-auth/registration/', include('rest_auth.registration.urls'))
My authentication class is rest_framework.authentication.TokenAuthentication
This rest API call works perfectly well.
When I register via this API I get the below response.
{
"key": "3735f13cd69051579156f98ffda338a2d7a89bb5"
}
I also want to include the user_id field in the response. How do I go about doing that. I tried extending the method get_response_data from class RegisterView(CreateAPIView): but unable to do so. Can someone please advise the best practice to achieve this. Code would be ideal. Thanks.
I want to use the rest-auth/registration/ url provided out of box by rest_auth.registration. I do not want to create a separate new URL for this.
My Settings.py as follows
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'sdAPI.apps.SdapiConfig',
'rest_framework',
'rest_framework.authtoken',
'rest_auth',
'rest_framework_swagger',
'rest_auth.registration',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.google',
'django_extensions',
]
# auth and allauth settings
LOGIN_REDIRECT_URL = '/'
SOCIALACCOUNT_QUERY_EMAIL = True
SOCIALACCOUNT_PROVIDERS = {
'facebook': {
'SCOPE': ['email', 'publish_stream'],
'METHOD': 'oauth2' # instead of 'oauth2'
}
}
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
)
}
SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
REST_SESSION_LOGIN = False
My urls.py as follows
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/',include('rest_auth.registration.urls')),
]
I think you only need to override the TOKEN_SERIALIZER option in your REST_AUTH_SERIALIZERS configuration.
from rest_framework.authtoken.models import Token
class TokenSerializer(serializers.ModelSerializer):
class Meta:
model = Token
fields = ('key', 'user')
Then, set it in your settings.py as shown in the docs,
REST_AUTH_SERIALIZERS = {
'LOGIN_SERIALIZER': 'path.to.custom.LoginSerializer',
'TOKEN_SERIALIZER': 'path.to.custom.TokenSerializer',
...
}