How to check if the current user is logged in django rest framework? how to notify other django app that the current user is logged? - django-rest-framework

I use ListCreateAPIView for POST and GET requests. I want to check if current user is logged in GET request.
How to get current user (if he logged) in GET methods ?
To make it work, i have to send with token , t's not what I want because if user is logout, user can not access listView.
I thought django signals,or to rewrite authorization.
I thought django signals, or to rewrite Permissions or Authorization.
class PropertyList(generics.ListCreateAPIView):
"""To create a property"""
permission_classes = [permissions.IsAuthenticatedOrReadOnly, ]
queryset = Property.objects.filter(published=True)
serializer_class = PropertySerializer
filterset_class = PropertyFilter
pagination_class = LimitOffsetPagination
#
# def perform_create(self, serializer):
# serializer.save(created_by=self.request.user)
# for _ in range(100):
# logger.info("Your log message is here")
def get_serializer_context(self):
context = super().get_serializer_context()
context['is_create'] = True
print(self.request.user)
if self.request.user.is_authenticated:
print(self.request.user)
current_user = self.request.user
context['user_favs'] = (Bookmark.objects.filter(
bookUser = current_user
).values(
))
else:
context['user_favs'] = False
return context
In get_serializer_context(self) , i want to get current user because i return properties that user has bookmarked.
I need to add token in my Get request to have current user but that's mean , we have to login to see properties , it's not what I want
settings
REST_FRAMEWORK = {
"DATE_INPUT_FORMATS": ["%d-%m-%Y"],
# 'DATETIME_FORMAT': "%d-%m-%Y %H:%M:%S",
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
# 'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_FILTER_BACKENDS': (
'django_filters.rest_framework.DjangoFilterBackend',
),
'EXCEPTION_HANDLER': 'dooba.utils.custom_exception_handler',
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
# 'DEFAULT_PARSER_CLASSES': (
# 'rest_framework.parsers.JSONParser',
# 'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
# )
}
As you can see

You can access user object in your APIView methods by self.request.user if there is no logged-in user, it should be AnonymousUser or else you should get the logged in user.
EDIT: Further research revealed that when you use JSONWebTokenAuthentication with IsAuthenticatedOrReadOnly returns 401 with expired tokens even if you make GET request. I recommend you to never put Authenticate header when making a GET request to your PropertyList view, that will solve your problem.

Related

Adding permissions to a django rest api

I am working on a django rest api and i want to add permission to it
. I decided to go with IsAuthenticatedOrReadOnly to allow none authenticated people to read only and allow authenticated people to add data
setting.py:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]}
views.py:
#api_view(['GET','POST'])
#permission_classes([IsAuthenticatedOrReadOnly])
def list_drinks(request, format=none):
if request.method == 'GET':
drinks = Drink.objects.all()
serializer = DrinkSerializer(drinks, many=True)
return Response(serializer.data)
if request.method == 'POST':
serializer = DrinkSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
when i try to access the api without authentification, i can only read but when i try to do a modification while adding a username and a password, i get the message "detail": "You do not have permission to perform this action." even though i am authenticated as admin (a superuser)
what's the problem?
Make sure you have the necessary authentication classes in your REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] settings.
For basic authentication add "rest_framework.authentication.BasicAuthentication" to the list.
If you are using the browsable API you need to add session authentication "rest_framework.authentication.SessionAuthentication"

Django rest framework authentication issue

I have custom token creating and decoding methods. Now everytime I get request I need to decode token to get request user or I get anonymous user. How can I decode it without repeating every time these lines?
auth = get_authorization_header(request).split()
if auth and len(auth) == 2:
token = auth[1].decode('utf-8')
id = decode_access_token(token)
You can create a middleware, where you decode the token and pass the info about the user to the class/function view
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
auth = get_authorization_header(request).split()
user = None
if auth and len(auth) == 2:
token = auth[1].decode('utf-8')
id = decode_access_token(token)
user = ... # get user
response = self.get_response(request, user)
# Code to be executed for each request/response after
# the view is called.
return response
And in your view
#method_decorator(SimpleMiddleware, name='dispatch')
class SimpleView(View):
def post(self, request, user):
pass

Getting user details from access token in Django rest framework -simple JWT

I am using React and Django rest framework for a project. I use Django rest framework simple JWT for authentication. Now, I want to display the username in the navbar after the user logs in. So, is there a way in simple JWT for returning user details from the access token generated after authentication, just like Djoser returns user credentials when supplied the access token?
Sorry if this question is silly but I was not able to find a solution to this anywhere.
if you want to obtain the information of the owner of the token you can consult it in REQUEST.
class ViewProtect(APIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def post(self, request, format=None):
token_user_email = request.user.email
token_user_username = request.user.username
pass
About the backend, basically I use this library
from restframework_simplejwt.tokens import AccessToken
The function AccessToken() take as input the string access_token_str and return the object access_token_obj.
To get the user_id, you can use the instruction
user_id=access_token_obj['user_id'].
In the following example I have created the function
get_user_from_access_token_in_django_rest_framework_simplejwt().
This function is just a wrapper around AccessToken()
Full code:
#Path current file
#/blabla/django/project004/core/view.py
from restframework_simplejwt.tokens import AccessToken
from django.contrib.auth.models import User
#Example data.
#access_token_str = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU'
def get_user_from_access_token_in_django_rest_framework_simplejwt(access_token_str):
access_token_obj = AccessToken(access_token_str)
user_id=access_token_obj['user_id']
user=User.objects.get(id=user_id)
print('user_id: ', user_id )
print('user: ', user)
print('user.id: ', user.id )
content = {'user_id': user_id, 'user':user, 'user.id':user.id}
return Response(content)
Credits:
#davesque;
https://github.com/jazzband/djangorestframework-simplejwt/issues/140
Update.
The string access_token_str I write in the file is just an example. You should pass it as argument.
Here's how I've done it.
On Django, I followed the steps described on this page in order to add the user's name inside the JWT token : https://django-rest-framework-simplejwt.readthedocs.io/en/latest/customizing_token_claims.html
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls, user):
token = super().get_token(user)
# Add name to token
token['name'] = user.get_full_name()
# You can add other information into the token here
return token
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
Then, I updated my urls.py to use the custom view:
path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
Finally, in my Vue.js application, I installed the jwt-decode package and used it like this:
const token = localStorage.getItem('access_token');
const decoded = jwt_decode(token);
console.log(decoded)
// decoded.name contains the user's full name
Note that I store the access token in the local storage beforehand.

login by one user and accesstoken of another user

I have implemented simpleJWT for token based authentication. I created a simple hello world test API.
While testing, I am logging with /rest-auth/login/ and for generating use /api/token/ - both working fine.
Now for testing, I am logging in with say user XYZ (having access rights for helloworld api) and generating token using another user ABC (not having access rights for helloworld api).
So now user XYZ is authenticated (ok) but I am having token of user ABC (ok).
Now, when I call the API with token generated for use ABC, I am able to access the helloworld api even if user ABC has no rights for the API !! Because user XYZ who has rights already logged in.
Problem is this will always be case when multiple users will be using the site. How to resolve ? Few code snippets also presented below :
My settings.py snipped
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
code basically a decorator which authenticate for users is as below
def user_is_ADM(fun_c):
#wraps(fun_c)
def wrapped(request, *args, **kwargs):
# 1 = ADM
if(request.user and request.user.is_authenticated) : <--- here is the issue
user_data = UserProfile.objects.get(user_id = request.user.id)
# user profile as as a user type
u = user_data.user_type
if u == 1:
return fun_c(request, *args, **kwargs)
else:
raise PermissionDenied
return wrapped
what should be my strategy in this case ?
EDIT
Modified my decorator as follows and it is working. Someone please comment if I am doing something wrong
def user_is_ADM(fun_c):
#wraps(fun_c)
def wrapped(request, *args, **kwargs):
juser = get_user(request)
if juser.is_authenticated:
user_jwt = JWTAuthentication().authenticate(Request(request))
if user_jwt is not None:
if request.user == user_jwt[0]:
k = user_jwt[0].userprofile.get_user_type_display()
if k == 'ADM':
return fun_c(request,*args,**kwargs)
else:
raise PermissionDenied
else:
raise PermissionDenied
else:
raise PermissionDenied
else:
raise PermissionDenied
return wrapped
check out this documentation https://www.django-rest-framework.org/api-guide/permissions/ (Custom permissions)
when setting a general permission setting (IsAuthenticated).
It is really authenticating users but not verifying their permissions at any time
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
if basic administrator and user authentication is not enough. you can implement a custom permission
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
"""
extracted from the documentation
"""
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
"""
add authentication logic and return a boolean value
"""
# ...
# return bool()
in the views
from rest_framework.views import APIView
from modulename.permissions import CustomerAccessPermission
class ExampleView(APIView):
"""
...
"""
permission_classes = (CustomerAccessPermission,)
def get(self, request, format=None):
"""
...
"""
Here is an example with django authentication permissions
from typing import Tuple
from rest_framework.permissions import BasePermission
class CustomPermission(BasePermission):
"""
...
"""
list_permissions: Tuple[str] = (
'modelname.view_modelname',
'modelname.add_modelname',
'modelname.change_modelname',
'modelname.delete_modelname',
)
def has_permission(self, request, view) -> bool:
return bool(
request.user.has_perms(self.list_permissions)
or
request.user and request.user.is_staff
or
request.user and request.user.is_superuser
)
summary
With regard to the syntax in general, you will not see any changes, you must import your permission or decorator in the view, the difference lies in the runtime and the way django will evaluate the permissions
Remembering that a decorator is nothing more than a summary way of saying func(func()).
so you should always evaluate the view and call your method modified by the decorator
instead, permissions in this framework are always defined as a list of permission classes. Before executing the main body of the view, each permission in the list is verified. If any permission verification fails, exceptions will be generated. Permission denied or exceptions. An unauthenticated exception will be generated and the main body of the view will not be executed. (Consult the documentation for a complete explanation)
You should evaluate which method is most appropriate for your case (performance, syntax, etc.).
# you can set your permission in the general settings to avoid importing into each file
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'modulename.permissions.CustomPermission',
),
# ...
}

django rest framework: custom permission for GET request

i have this view handling only /GET/ request to display all authors only if the logged user is superuser
class AuthorView(generics.ListAPIView):
serializer_class = AuthorSerializer
queryset = Author.objects.all()
permission_class = (IsSuperUser,)
And the permission for superuser:
class IsSuperUser(permissions.BasePermission):
def has_permission(self, request, view):
user = request.user
return user.is_authenticated() and user.is_superuser
The permission does not seems to be working, placed the pdb in has_permission the control does not seems to coming there.
What am i missing ?
It should be:
permission_classes = (IsSuperUser,)
and not
permission_class = (IsSuperUser,)

Resources