Why my class based view is not authenticating my user? - python-3.x

I am using rest_framework_simplejwt for authentication. My user/urls.py looks like this:
from django.contrib import admin
from . import views as user_views
from user.security.jwt_auth import GetToken
admin.autodiscover()
# Setup the URLs and include login URLs for the browsable API.
urlpatterns = [
path('login', GetToken.as_view(), name='login'),
]
This route works well and it returns the access_token and the refresh_token.
Now this is my client/urls.py
from django.urls import path, include
from django.contrib import admin
from client import views as client_views
admin.autodiscover()
urlpatterns = [
path('client', client_views.ClientList.as_view()),
path('client/<int:pk>', client_views.ClientDetail.as_view()),
path('create_client', client_views.create_client)
]
Here I am trying to use a decorator for the class. The decorator works well, the problem is that inside the decorator function the request.user does not exist, instead I have to do request.request.user. And when I do that the user is AnonymousUser. I already tried this decorator on the function based view by sending the access_token in the Authorization header and I am able to get the correct user, in other words the JWT Auth works automatically. Then Why it is not working in this scenario?
user/security/decorators.py
def authentication_for_class(function):
def wrap(request, *args, **kwargs):
# todo: Finish permissions
print(request.request.user)
if request.request.user.is_anonymous:
return JsonResponse({"detail": "You do not have permission to perform this action."}, status=403)
return function(request, *args, **kwargs)
wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__
return wrap
And this is my client/view.py
from user.security.decorators import authentication_for_class
class ClientList(APIView):
#authentication_for_class
def dispatch(self, request, *args, **kwargs):
return super(ClientList, self).dispatch(request, *args, **kwargs)

Related

How to Refresh a OAuth2 Token by using Django OAuth Toolkit in custom Views?

What I'm doing?
I have a requirement where there will be separate authorisation server and a resource server.
I am using Resource owner password based grant type.
I have implemented Custom Introspection View and Get Token View. (Following this and this: I have used the DOT's base class to implement my own introspection API, will add it at the end.)
For both Custom Views I created, I have added it to the urls.py manually referring to it.
What's happening now?
Turns out, you gotta refresh token using the same /token/ url which you used to get a access token. The only difference is you gotta change the grant type to refresh_token when you wanna refresh token.
It does not get processed as I have not implemented or am able to implement the refresh token. I am happy with the pre-existing internal refresh token mechanism as I don't require special/custom stuff to be in it but as I'm using a custom token view, grand_type = refresh_token is not hitting the oauthlibs refresh_token view. (My observation)
urls.py
from django.contrib import admin
from django.urls import path, include
from project.apis import (
ClientCreateTokenView,
ResourceServerIntrospectView
)
urlpatterns = [
path('admin/', admin.site.urls),
path('o/token/', ClientCreateTokenView.as_view(), name='token_obtain_pair'),
path('o/introspect/', ResourceServerIntrospectView.as_view(), name='introspect_token'),
path('o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
]
apis.py
from django.http import HttpResponse
from oauth2_provider.views.base import TokenView
from oauth2_provider.views import IntrospectTokenView
from django.utils.decorators import method_decorator
from django.views.decorators.debug import sensitive_post_parameters
from oauth2_provider.models import get_access_token_model
from oauth2_provider.signals import app_authorized
import json
from iam_management.models import AuthorisedClients
from rest_framework import status
from base64 import b64decode
from django.contrib.auth.models import User
import time
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse
import calendar
class ResourceServerIntrospectView(IntrospectTokenView):
"""
Implements an endpoint for token introspection based
on RFC 7662 https://tools.ietf.org/html/rfc7662
"""
#staticmethod
def get_token_response(token_value=None, resource_server_app_name=None):
try:
token = (
get_access_token_model().objects.select_related("user", "application").get(token=token_value)
)
except ObjectDoesNotExist:
return JsonResponse({"active": False}, status=200)
else:
authorised_clients = AuthorisedClients.objects.filter(user=token.user).first()
if token.is_valid() and resource_server_app_name in json.loads(authorised_clients.authorised_apps):
data = {
"active": True,
"exp": int(calendar.timegm(token.expires.timetuple())),
}
if token.application:
data["client_id"] = token.application.client_id
if token.user:
data["username"] = token.user.get_username()
return JsonResponse(data)
else:
return JsonResponse({"active": False}, status=200)
def get(self, request, *args, **kwargs):
return HttpResponse(status=405)
def post(self, request, *args, **kwargs):
"""
Get the token from the body parameters.
Body: { "token": "mF_9.B5f-4.1JqM" }
"""
if "token" in request.POST and "app_name" in request.POST:
return self.get_token_response(request.POST["token"], request.POST["app_name"])
else:
return HttpResponse(status=400)
class ClientCreateTokenView(TokenView):
#method_decorator(sensitive_post_parameters("password"))
def post(self, request, *args, **kwargs):
try:
username = request.POST["username"]
app_name = request.POST["app_name"]
client_id = \
b64decode(request.META["HTTP_AUTHORIZATION"].split(" ")[1].encode("utf-8")).decode("utf-8").split(":")[
0]
except:
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
authorized_client = AuthorisedClients.objects.filter(user=User.objects.get(username=username),
client_id=client_id).first()
if not authorized_client:
return HttpResponse(status=status.HTTP_401_UNAUTHORIZED)
authorised_apps = json.loads(authorized_client.authorised_apps)
if app_name.lower() not in authorised_apps:
return HttpResponse(status=status.HTTP_401_UNAUTHORIZED)
url, headers, body, return_status = self.create_token_response(request)
if return_status == 200:
body = json.loads(body)
access_token = body.get("access_token")
if access_token is not None:
token = get_access_token_model().objects.get(token=access_token)
app_authorized.send(
sender=self,
request=request,
token=token
)
if "scope" in body.keys():
del body["scope"]
body = json.dumps(body)
response = HttpResponse(content=body, status=return_status)
for k, v in headers.items():
response[k] = v
return response
I know that I am not really following the standards and putting custom stuff here for more checks but that's just my use case. I am unable to find anything on refresh token on DOT even though it is a famous and maintained package.

DRF's not calling post() method when receiving POST request

I have a viewset like this:
class MyViewSet(CreateAPIView, RetrieveModelMixin, ListModelMixin, GenericViewSet):
queryset = MyModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
import pdb; pdb.set_trace()
class MySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = MyModel
fields = ['id', 'field1', 'field2'] #only field1 is required in the model
The GET requests for list, and retrieve works perfectly. When I make a POST request, sending the field1 I get a status 201 and a new record is added to the database, so it works too.
But my method MyViewSet.post() that should overwrite the same one from generics.CreateAPIView never gets called.
Not only that, but I've tried to add the pdb.set_trace(), literally inside the generics.CreateAPIView.post() and in the CreateModelMixin.create() functions and neither stopped once I made the POST request.
So something else is handling this POST request and inserting into the DB, I just don't know what. And how can I overwrite it, so I can customize what should be done with a post request?
PS.: Also, I don't think it's a routing problem, my urls.py:
from rest_framework import routers
from myapp.views import MyViewSet, AnotherViewSet
router = routers.DefaultRouter()
router.register(r'route_one', MyViewSet)
router.register(r'route_two', AnotherViewSet)
I think you need to use the exact class in order to use POST api.
class MyView(CreateModelMixin, ListModelMixin, generics.GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MySerializer
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
In urls.py
from django.urls import path
from .views import MyView
urlpatterns = [
path('route_one', MyView.as_view(), name="my_view_detail")
]

how do i wrtite django fbv to class based view

I have two user types a and b i need to write the below fbv into class based Logoutview(auth.view) how do i write the below fbv to cbv
views.py
#login_required
def logout(request):
if request.user.usertype_a:
logout(request)
return redirect(reverse('user_a_login'))
else:
logout(request)
return redirect(reverse('user_b_login'))
Give this a try
from django.views import View
class LogOutView(View):
def get(self, request, *args, **kwargs):
logout(request)
if request.user.usertype_a:
return redirect(reverse('user_a_login'))
return redirect(reverse('user_b_login'))
Or you can Use LogoutView and override its dispatch method for custom redirections
Try to add this to your urls.py:
from django.contrib.auth import views as auth_views
path('logout/', auth_views.LogoutView.as_view(), name='logout'),

hi i am getting "CSRF Failed and CSRF cookie not set." error

{"detail": "CSRF Failed: CSRF cookie not set."} error in postman , i am using django rest_framework for developing ios android backend .
when i first time clear all cookies and use my login api is working fine
this will give me all info about user as per my code but after that when i try to hit any api using post method its always give crsf failed.
i also use csrf_exempt decorator in view and urls.py and also tried CsrfExemptMixin from brace package.
my login code is
from django.contrib.auth import login,logout
from django.shortcuts import render,redirect
# local py files
from .models import *
from .serializers import *
from app_apis.models import *
# third party
from rest_framework import (generics,
permissions)
from knox.views import LoginView as KnoxLoginView
from rest_framework.response import Response
from rest_framework.authtoken.serializers import AuthTokenSerializer
from knox.models import AuthToken
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from braces.views import CsrfExemptMixin
from django.middleware.csrf import get_token
# Register API
class RegisterView(CsrfExemptMixin,generics.GenericAPIView):
serializer_class=RegisterUserSerializer
#method_decorator(csrf_exempt)
def post(self,request,*args, **kwargs):
serializer=self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
print
logout(request)
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
class LoginAPI(CsrfExemptMixin,KnoxLoginView):
permission_classes = (permissions.AllowAny,)
def get(self,request):
example={
"username":"user_name",
"password":"Your Password"
}
return Response(example)
#method_decorator(csrf_exempt)
def post(self, request, format=None):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
user_id_main=user.id
user_name=user.username
user_data=[user_id_main,user_name]
print(user_data)
projects=ProjectTable.objects.filter(created_by_id=user_id_main).values_list('name')
project_names=projects
login(request, user)
temp_list=super(LoginAPI, self).post(request, format=None)
temp_list.data["project_list"]=project_names
temp_list.data["user_data"]=user_data
temp_list.data['csrf_token']=get_token(request)
return Response({"data":temp_list.data})
# logout
def logout_view(request):
logout(request)
return redirect("user_profile:login")
please guide me . thanks in advance
Do not use rest_framework.authentication.SessionAuthentication in DEFAULT_AUTHENTICATION_CLASSES
Reference link: https://stackoverflow.com/a/56101653/217586
use corsheaders in installed app https://pypi.org/project/django-cors-headers/ use and follow the documentation

Django: How to fetch id in class based views?

views.py
from paitent.mixini import HttpResponseMixin,SerializeMixin
from paitent.models import Paitent_Details
class PaitentCRUDCBV(View, HttpResponseMixin, SerializeMixin):
def get(self, id, *args, **kwargs):
paitent = Paitent_Details.objects.get(id=id)
json_data = self.render_to_serialize([paitent,])
return self.render_to_http_response(json_data)
urls.py
urlpatterns = [
url(r'^api/json',views.PaitentCRUDCBV.as_view()),
]
My requirement is based on id i have to fetch particular row form data base,from Frontend side i am passing id in url like:(url: "http://127.0.0.1:8000/api/json/?id=2").But i am not finding id inside my class ,don't know where i am doing wrong. please help me.
You can use query_params in view:
def get(self, request):
id = self.request.query_params.get('id')
....
You can get more information from documentation
1)I have edited your following code, you have to pass *request* in your function,
2)Inside the function calling request.query_params.get, you will get parameters value from the url
from paitent.mixini import HttpResponseMixin,SerializeMixin
from paitent.models import Paitent_Details
class PaitentCRUDCBV(View, HttpResponseMixin, SerializeMixin):
def get(self, request, *args, **kwargs):
id=self.request.query_params.get('id')
paitent = Paitent_Details.objects.get(id=id)
json_data = self.render_to_serialize([paitent,])
return self.render_to_http_response(json_data)

Resources