Post from Angular 5 front-end to Django Rest Framework back-end - django-rest-framework

I am trying to create a post request from Angular 5 to DRF. The field is a form that a user submits. I created the serializer and i can post something from DRF interface
models.py
class UserForm(models.Model):
id_user_form = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, db_column='idUser', unique=False)
name = models.CharField(max_length=50)
type = models.CharField(max_length=25)
location = models.CharField(max_length=200)
serilizers.py
`class UserFormSerializer(serializers.ModelSerializer):
class Meta:
model = UserForm
fields = ('user', 'name', 'type', 'location')
def create(self, validated_data):
user_data = validated_data.pop('user')
user_form = UserForm.objects.create(user_id=user_data, **validated_data)
return user_form
views.py
class FormSubmit(generics.ListCreateAPIView):
queryset = UserForm.objects.all()
serializer_class = UserFormSerializer
When i try to post it via Angular I get this error:
Forbidden (CSRF token missing or incorrect.): /api/form/
Am I doing something wrong?

Had the exact same problem when I wanted to upload a profile picture to my Django REST backend.
You have 2 options, basically.
The first one is disabling the CSRF checks, which are by default enforced by DRF. Have a read here. You may do this for testing purposes.
The second option would be to pass the CSRF Token inside your request header. To do that, have a look at the $cookies API.
With that, you can get the token out of the cookie and paste it into your header like so: 'X-CSRFToken': your-csrf-token-here.
You can verify this by opening your dev tools inside the browser and navigating to your site's cookies. You should see one called csrftoken there.
I hope this sent you on the right track.

Related

How can i use Simple JWT for custom User Model

I am managing my User Model (for customers), but i don't know how can i use simple-jwt for my Customer Model with it's custom Login View.
models.py
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
password = models.CharField(max_length=100)
and also, i want to manage my customer session by saving the Refresh Token,
can anyone please tell me how can i achieve that.
After some research, I came to the conclusion that Simple JWT doesn't have any special support for user models that are not derived from AbstactUserModel.
It means if you are managing the Customer model, either you need to extend it from AbstactUserModel or you should use jwt instead of Simple jwt.
First install simple jwt with the command
pip install djangorestframework-simplejwt
You must then configure your django project to use the libary with following option in settings.py
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
...
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
...
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'UPDATE_LAST_LOGIN': False,
'ALGORITHM': 'HS256',
'SIGNING_KEY': settings.SECRET_KEY,
'VERIFYING_KEY': None,
'AUDIENCE': None,
'ISSUER': None,
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'JTI_CLAIM': 'jti',
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
In your root urls.py add the following
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
...
]
Simple JWT by default only sends user id in the token. You can customize it further to send more information in your serializers.py by doing the following
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
"""Customizes JWT default Serializer to add more information about user"""
#classmethod
def get_token(cls, user):
token = super().get_token(user)
token['name'] = user.name
token['email'] = user.email
token['is_superuser'] = user.is_superuser
token['is_staff'] = user.is_staff
return token
Then in your views.py add the following
from users import serializers
class CustomTokenObtainPairView(TokenObtainPairView):
# Replace the serializer with your custom
serializer_class = serializers.CustomTokenObtainPairSerializer
You can read more here
I could fix this problem adding 'rest_framework_simplejwt' to INSTALLED_APPS after the app that has the custom user model.
in your views.py file, import this
from rest_framework_simplejwt.tokens import RefreshToken
next, create a refresh token in def post - the one you use for logging in
def post(self, request):
...
refresh = RefreshToken.for_user(user)
...
return the generated refresh token and access token in the response body
return Response(
{
'refresh': str(refresh),
'access': str(refresh.access_token),
},
status = status.HTTP_200_OK
)
What I have suggested is a simple and super basic implementation of what I believe you are looking for. I got it from here. But if you want a better and more customized, neater implementation, refer this article.

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.

Parameters URL with DRF routers

I'm using Django Rest Framework for created a API. In this project i want to capture parameters in the URL. For example i want to capture the username and password of a user and my idea is like this:
http://localhost:8000/accounts/login/?unsername=username&password=password
But i cant, I' usin routers and django-filter, but i cant get the parameters url. My project files are there:
view.py:
class AccountsData(viewsets.ModelViewSet):
queryset = models.UserData.objects.all()
serializer_class = serializers.AccountsDataSerializer
permission_classes = (IsAuthenticated,)
filter_backends = (filters.DjangoFilterBackend,)
filterset_fields = ['username', 'password']
lookup_url_kwarg = 'username'
#action(methods=['get'], detail=True, url_name='login', url_path='login')
def login(self, request, pk=None):
return Response({"Login successfully"}, 200)
urls.py:
from api import views
router = routers.SimpleRouter()
router.register(r'accounts', views.AccountsData)
Request query parameters have nothing to do with routing, they are passed with the request independently of how you configure the route. You have access to them in request.query_params, for example, request.query_params.get('username') would get the value of the username parameter.
Being said that, your idea has a terrible mistake: password or any kind of confidential data should NEVER go in query parameters, you should use an http verb that carries the data in its body (POST, for example).

Django rest framework - exclude endpoint from authentication

I need to make view accessible without authentication, based on a variable passed in urls.py.
My idea is something like this:
urls.py
url(r'^oidc-api/', include('api.urls'), {'logged': True})
views.py
class ExampleViewSet(ModelViewSet):
if logged: # How can I get this variable, passed in urls.py?
permission_classes = () # This will exclude current view from authentication
queryset = Widget.objects.filter(visible=True)
serializer_class = ExampleSerializer
filter_backends = (DjangoFilterBackend,)
filter_fields = ('example_id',)
However, I can not access logged variable that is passed from urls.py.
John
You can't do that.
What you could do is, remove those permission classes from the views manually or set those to an empty set as,
class ExampleViewSet(ModelViewSet):
permission_classes = ()

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