Django Rest-framework, JWT authentication - django

I'm newbie in Django Restframework. I use JWT to make login, register API, everythings worked well, I want to GET a user information with authenticated (tokens). This is my code for UserViewSet
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
authentication_classes = [IsAuthenticated,]
I've tested on Postman but i received: "'IsAuthenticated' object has no attributes 'authenticate'"
REST_FRAMEWORK = {
'NONE_FIELD_ERRORS_KEY':'error',
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
Could you please to help me to solve this promblem? Thank you very much.

IsAuthenticated is not an authentication class. It's a permission class.
You would put it in permission_classes to allow any authenticated user access to that view set, while authentication (the mechanism of figuring out who the user for that request is) would be handled by that default JWT authentication:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated,]

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.

Different authentications and permissions in ModelViewSet - Django REST framework

This question is similar to this one: Using different authentication for different operations in ModelViewSet in Django REST framework, but it didn't work for me.
I've got the following viewset:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = UserProfile.objects.none()
permission_classes = [SpecialPermission]
SpecialPermission looks like this:
class SpecialPermission(IsAuthenticated):
def has_permission(self, request, view):
if request.method == 'POST':
return True
return super().has_permission(request, view)
REST framework settings:
"DEFAULT_AUTHENTICATION_CLASSES": ["backend.api.authentication.ExpiringTokenAuthentication"],
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
I want to everybody to be able to post to UserViewSet but every other method should require Authentication. However, with the code above I get an Unauthorized Response on post.
What do I need to change?
Although it can be done, this requirement imo does not justify this ifology as auth/user related stuff should be clean and secure.
Instead extract POST method from this viewset to its own class.
class UserViewSet(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
serializer_class = UserSerializer
queryset = UserProfile.objects.none()
permission_classes = [SpecialPermission]
class CreateUserView(CreateAPIView):
serializer_class = UserSerializer
queryset = UserProfile.objects.none()
authentication_classes = []
if you really want to disable authentication in this viewset I'd rather recommend this
def get_authenticators(self):
if self.action == 'create':
return []
return super().get_authenticators()
That's more explicit than your solution.
I figured it out: Making perform_authentication lazy solved my problem. Now I can post but authentication still runs on all other methods where it is needed.
def perform_authentication(self, request):
"""
Perform authentication on the incoming request.
Note that if you override this and simply 'pass', then authentication
will instead be performed lazily, the first time either
`request.user` or `request.auth` is accessed.
"""
pass

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

Django restful API - get user id with token

How to obtain User ID from Django API having authentication token?
Basically, I want to send authentication token and get back User id.
I have tried this solution: How can I return user ID with token in Django?
but it is returning token with provided username and password, which is not what I want.
#myapp/views.py
class UserIdViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
def get_queryset(self):
return User.objects.filter(id=self.request.user.id)
#myapp/urls.py
router.register(r'api/user-id', userviews.UserIdViewSet, base_name="UserId")
sort out the problem. Basically created View set and sort this out against current user.
What type of authentication you use ?
If for example, you use TokenAuthentication from rest_framework, you can have a look how this class implements request authentication.
You can find there methods authenticate and authenticate_credentials and I believe that there - you will find your answer how to get the user.
In the perform_create method you can assign the user to your model
class EmailViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication)
permission_classes = (IsAuthenticated,)
queryset = Email.objects.all()
serializer_class = EmailSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)

Django not recognizing my Token?

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.