Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Creation and Custom Responses #34

Open
AustinStehling opened this issue Jul 17, 2018 · 5 comments
Open

User Creation and Custom Responses #34

AustinStehling opened this issue Jul 17, 2018 · 5 comments

Comments

@AustinStehling
Copy link

David, thanks for the great package.

I had a couple of issues I was running into that hopefully have an easy fix.

First was authenticating Users upon account creation. I tried implementing a serializer that inherited from TokenObtainPairSerializer.

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super(MyTokenObtainPairSerializer, cls).get_token(user)
        access = token.access_token
        return token, access

Upon authentication, I would add the token to the payload I passed to the frontend. The problem with this function is that it returned a jti, expiration and token type, but the actual token always returned None.

The other issues I wanted to tackled was modifying the MyTokenObtainPair end point to include user information in the Response.

Thanks for the guidance.

@AustinStehling AustinStehling changed the title User Creation and Custom Response User Creation and Custom Responses Jul 17, 2018
@ckeeney
Copy link

ckeeney commented Sep 9, 2018

I have this working reasonably well, but the code could probably be a bit cleaner.

If I post a username and password to this view, a User is created and the response contains my access tokens with a claim added for the user's email address.

from rest_framework import serializers, permissions, status
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
from rest_framework.validators import UniqueValidator
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from bp_auth.models import CustomUser as User


class SignupSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)
    email = serializers.CharField(
        validators=[UniqueValidator(queryset=User.objects.all())]
    )

    class Meta:
        model = User
        fields = ('email',  'password')


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super(MyTokenObtainPairSerializer, cls).get_token(user)
        token['email'] = user.email
        return token


class RegisterUsers(CreateAPIView):
    serializer_class = SignupSerializer
    permission_classes = (permissions.AllowAny,)

    def post(self, request, *args, **kwargs):
        serialized_user = SignupSerializer(data=request.data)
        if serialized_user.is_valid():
            User.objects.create_user(
                serialized_user.initial_data['email'],
                serialized_user.initial_data['password']
            )

            tokens = MyTokenObtainPairSerializer(request.data).validate(request.data)
            return Response(tokens, status=status.HTTP_201_CREATED)
        else:
            return Response(serialized_user._errors, status=status.HTTP_400_BAD_REQUEST)

@jemmycalak
Copy link

I have try code from @ckeeney and then i have case , response become
[
"No active account found with the given credentials"
]

I think, that code must use table User Auth, becaus I use custom table user to this code.. how can i Fix that ? should i use custom JWT for this case ? thanks

@bourou01
Copy link

bourou01 commented Feb 20, 2019

Hi,
here an exemple with a custom user model from sqlalchemy
As recommended in the doc, I used the JWTTokenUserAuthentication authentication class

serializer.py

from common.model.shared.User import User
from common.businesslogic.persistance.UserBL import UserBL
from rest_framework import fields
from rest_witchcraft.serializers import ModelSerializer
from rest_framework.validators import UniqueValidator
from common.config.database.connection import ConnectorPostgres, ConnectorPostgresTest
from rest_framework.reverse import reverse as api_reverse
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

from django.utils.six import text_type

userBL = UserBL().connect(conn = ConnectorPostgresTest(), autocommit=False)
session = userBL.session


class SignupSerializer(TokenObtainPairSerializer):
    uri             = fields.SerializerMethodField(read_only=True)
    username        = fields.CharField( validators=[UniqueValidator(queryset=userBL.getAll())] )
    password        = fields.CharField(write_only=True)

    class Meta:
        model = User
        session = session
        fields = [
            'user_id',
            'username',
            'password',
            'uri'
        ]
        
    @classmethod
    def get_token(cls, user):
        token = super(SignupSerializer, cls).get_token(user)
        # Add custom claims
        #token['username'] = user.username
        # ...
        return token
        

    def validate(self, attrs):
        user = userBL.getUserAccount(attrs.get('username'), attrs.get('password'))
        data = {}
        data['username'] = user.username
        data['email'] = user.email
        refresh = self.get_token(user)
        data['token'] = text_type(refresh)
        data['refresh'] = text_type(refresh)
        data['access'] = text_type(refresh.access_token)

        return data



    def get_uri(self, obj):
        request = self.context.get('request')
        return api_reverse("api-user:detail", kwargs={"username": obj.username}, request=request)

view.py

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView
)


from rest_framework import generics, permissions, status
from rest_framework.views import APIView
from rest_framework.response import Response

from .serializers import SignupSerializer, userBL


from common.model.shared.User import User
from common.businesslogic.persistance.UserBL import UserBL

from rest_framework_simplejwt import authentication


class AuthAPIView(TokenObtainPairView):
    authentication_classes  = [authentication.JWTTokenUserAuthentication]
    serializer_class        = SignupSerializer
    permission_classes      = [permissions.AllowAny]
    queryset                = userBL.getAll()
    

    def post(self, request, *args, **kwargs):
        data = request.data
        login = data.get('username')
        password = data.get('password')

        response={"detail":"Invalid credentials"}

        user = userBL.getUserAccount(login, password)
        if (user != None):
            serializer = self.get_serializer(data=request.data)    
            response = serializer.validate(request.data)
        else:
            response = {"detail":"Invalid credentials"}
            return Response(response, status=status.HTTP_401_UNAUTHORIZED)

        return Response(response, status=status.HTTP_201_CREATED)

This is a copy/past of my prod code so feel free to ask for more details

@CZZLEGEND
Copy link

from rest_framework_simplejwt.tokens import RefreshToken

def get_tokens_for_user(user):
refresh = RefreshToken.for_user(user)

return {
    'refresh': str(refresh),
    'access': str(refresh.access_token),
}

The above function get_tokens_for_user will return the serialized representations of new refresh and access tokens for the given user. In general, a token for any subclass of rest_framework_simplejwt.tokens.Token can be created in this way.

@puroh
Copy link

puroh commented Jul 31, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants