Django not recognizing my Token? - django

I'm using Django Rest Framework on the backend and an ember-cli app on the frontend. The authentication is working correctly, but there seems to be a hole somewhere in authorization.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}
# views.py
class CurrentUserView(APIView):
"get the data for the current authenticatd user"
permission_classes = (IsAuthenticated,)
def get_queryset(self, request):
queryset = User.objects.filter(username=request.user.username)
return queryset
def get(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)
When I make a request to this endpoint /v1/me/ it responds back with a 403. When I take off the permission class, I get back {"id":null,"username":"","is_active":false} because it doesn't know who I am.
Also, when I use the browsable API, the /v1/me URL works correctly.
On the Ember side of things, I login with my account and correctly get back my Token. In the request the Authorization: Token asdf1234asdf1234asdf1234 is being passed. I would think Django takes that token and knows who I am? Am I missing something?

Try something like
from rest_framework import authentication
class TokenAuthView(APIView):
authentication_classes = (authentication.TokenAuthentication,)
Then,
class CurrentUserView(TokenAuthView)

In the setting you need to add auth_token.
# settings.py
INSTALLED_APP = ('rest_framework.authtoken',)
You don't need to add the authentication_classes on every view.

Related

JWT authentication returns AnonymousUser in Django Rest Framework with SimpleJWT

I am opening this question as a last resort.
I am learning JWT and want to implement it on my django app. I didn't have any issues regarding Basic auth and Token auth, but JWT doesn't authenticate my user...
This is my settings.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
'api.permissions.AdminOrTeacherOnly'
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]
}
This is my view:
class StudentList(APIView):
authentication_classes = []
permission_classes = [AdminOrTeacherOnly]
def get(self, request, format=None):
students = Student.objects.all()
serializer = StudentListSerializer(students, many=True)
if not serializer.data:
return Response(status=status.HTTP_204_NO_CONTENT)
return Response(serializer.data, status=status.HTTP_200_OK)
This is my AdminOrTeacherOnly permission class:
class AdminOrTeacherOnly(permissions.BasePermission):
"""
Object-level permission to only allow teachers of a student to edit.
Assumes the model instance has an `owner` attribute.
"""
message = 'Only admin or teacher can edit student detail.'
def has_permission(self, request, view):
# Only teacher and/or admin user will be able to,
# edit and/or list this view.
is_staff = bool(request.user and request.user.is_staff)
is_teacher_group = str(request.user.groups.all().first()) == 'teacher'
return is_staff or is_teacher_group
I am able to get refresh and access token successfully:
Then, I am adding this to Headers as follows and send a request:
On debugger, when it enters the permission class:
Here, request.user returns <django.contrib.auth.models.AnonymousUser object at 0x104f5afd0>
I don't know what I am missing. Looked at related questions but couldn't find anything helpful regarding the SimpleJWT.
You're overriding authentication_classes here:
class StudentList(APIView):
authentication_classes = []
Add JWTAuthentication to that list.

{ "detail": "CSRF Failed: CSRF token missing or incorrect." }

hello guys . I try to register a new Product in my app using DRF and Postman.
when I send a request I get this error.
the problem is just about my csrf_token.
I'll be thankfull if you help me.....
this is my view
class ProductViewSet(viewsets.ModelViewSet):
authentication_classes = (SessionAuthentication,TokenAuthentication)
permission_classes = [IsAdminUser]
queryset = ProductInfo.objects.all().order_by('-id')
serializer_class = ProductSerializer
filter_backends = (filters.SearchFilter,)
search_fields = ['title','code','owner__username']
I don't have any problem for GET request.
Django requires CSRF token in POST request by default. to avoid CSRF tokens.
Don't use SessionAuthentication as authentication class, coz, it will force you to add CSRF token.
If you still want to use SessionAuthentication then You can use it overrideing
def enforce_csrf(self, request): method
Try below this:
from rest_framework.authentication import SessionAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
pass
and use it in your views:
authentication_classes = (CsrfExemptSessionAuthentication ,TokenAuthentication)
If you want to use it globally, you can place it in your REST_FRAMEWORK settings.py file like this:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'myapp.path-to-file.CsrfExemptSessionAuthentication'
],
}
Please make sure you add correct file path in the REST_FRAMEWORK settings
To authenticate with the token.
You must request like this:
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
Also make sure you added this in your INSTALLED_APP:
INSTALLED_APPS = [
''''
'rest_framework',
'rest_framework.authtoken',
]
More details can be found here: https://www.django-rest-framework.org/api-guide/authentication/
Because you don't need csrf_token for GET method.
you can set your csrf_token in header like this:
X-CSRFToken: your_csrf_value
so instead of using Cookie add X-CSRFToken to your header in POSTMAN.

How do I alter my API request based on a field from the user?

What I would like is an API request that gives me data based on a field from the User.
i.e. If the User is premium, give all of the data, otherwise, give a subset of that data.
This is easy enough, as shown in the DRF
filtering documentation:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
user = self.request.user
return Purchase.objects.filter(purchaser=user)
The problem:
I currently have it set up so anyone trying to access the API needs a Token. But, I'd like a 'Guest' user (someone who is not logged in) to still be able to see some data from my API.
I am using these Django Rest Framework settings:
REST_FRAMEWORK = {
"TEST_REQUEST_DEFAULT_FORMAT": "json",
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}
You can override the permissions for individual views.
from rest_framework import permissions
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
Then you might want to alter the behaviour in get_queryset if the user is not logged in
if request.user.is_anonymous:
# do something different

Unable to get user id with token by django rest framework?

I am using django Django=2.1.7 and rest framework djangorestframework=3.9.2 This is my url for login
path('rest-auth/', include('rest_auth.urls')),
After authentication I got token but I need user id too. I tried to override the post method of rest_framework.authtoken.views.py file with the following code
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
context = {
'token': token.key,
'user': user.id
}
return Response({'context': context})
Please help me figure out how to get user id with the token. This is my college project.
Note: I find many answers on stack overflow but none is helpful.
Use this Django RestFramework token authentication in order to use authentication. Here you can see how to authenticate, however if you want to use token authentication by default for all views you should add it in settings.py file as :
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'rest_framework.authentication.TokenAuthentication',
...
),
}
or you should add it manually to views which requires token authentication. And in this views you can get authenticated user as request.user or self.request.user.
from rest_framework.authentication import TokenAuthentication
class ViewSetName(ViewSet):
authentication_classes = [TokenAuthentication]

Django Rest Framework. Custom permission with JSONWebTokenAuthentication

I have a need to write a custom permission (deriving from BasePermission) for one of my endpoints where:
If the method is POST, it's open for everyone (e.g. returns true)..
however, if the method if PUT or GET it should be authenticated with JSONWebTokenAuthentication to figure out if to clear or reject the request.
Typically, I know how to add this into my APIView class
authentication_classes = ([JSONWebTokenAuthentication])
But how do I check whether the user is already authenticated with JSONWebTokenAuthentication in case the HTTP method is PUT or GET in my Custom Permission class? Is there something like IsJSONWebTokenAuthenticated somewhere?
You need to write a custom permission for your view,
permissions.py
class CustomPermission(BasePermission):
def has_permission(self, request, view):
if (request.method =='POST' or (request.user and request.user.is_authenticated())):
return True
return False
Then, you need to add to your settings.py,
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES':
('rest_framework.permissions.IsAuthenticated', ),
'DEFAULT_AUTHENTICATION_CLASSES':
('rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication', ),
}
Then add the permission to your permission_classes of the view,
from .permissions import CustomPermission
class YourView(APIView):
permission_classes = (CustomPermission, )