0

I have used Django Rest Framework for Rest API and django-oauth-toolkit for token based authentication. I have designed and api for user registration. When user is registered, a token is generated and saved to the database. I want user login from that token. I mean a token based authentication because i want to develop a mobile application. I can get access_token using curl when sending request for logging in but how do i implement in view so that app sends a post request to 127.0.0.1:8000/o/token asking for the token so that the request contains username, password, client_id and client_secret. The server then receives the credentials and if they are valid it returns the access_token. The rest of the time it should query the server using that token.

views.py

class UserLoginAPI(APIView):
    permission_classes = [AllowAny]
    serializer_class = UserLoginSerializer

    def post(self, request, *args, **kwargs):
        access_token = AccessToken.objects.get(token=request.POST.get('access_token'), expires__gt=timezone.now()) # error is shown here. I get None
        data = request.data
        serializer = UserLoginSerializer(data=data)
        if serializer.is_valid(raise_exception=True):
            new_data = serializer.data
            return Response(new_data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py

class UserCreateSerializer(ModelSerializer):
    class Meta:
        model = User
        extra_kwargs = {"password": {"write_only": True}}

    def create(self, validated_data):
        username = validated_data['username']
        first_name = validated_data['first_name']
        last_name = validated_data['last_name']
        email = validated_data['email']
        password = validated_data['password']
        confirm_password = validated_data['password']
        user_obj = User(
                username = username,
                first_name = first_name,
                last_name = last_name,
                email = email
            )
        user_obj.set_password(password)
        user_obj.save()
        if user_obj:
            expire_seconds = oauth2_settings.user_settings['ACCESS_TOKEN_EXPIRE_SECONDS']
            scopes = oauth2_settings.user_settings['SCOPES']

            application = Application.objects.get(name="Foodie")
            expires = datetime.now() + timedelta(seconds=expire_seconds)
            access_token = AccessToken.objects.create(user=user_obj, 
                                                    application=application,
                                                    token = generate_token(),
                                                    expires=expires, 
                                                    scope=scopes)
        return validated_data


class UserLoginSerializer(ModelSerializer):
    # token = CharField(allow_blank=True, read_only=True)
    username = CharField()
    class Meta:
        model = User
        fields = [
            'username',
            'password',
            # 'token',

        ]
        extra_kwargs = {"password":
                            {"write_only": True}
                            }
Serenity
  • 3,884
  • 6
  • 44
  • 87

1 Answers1

0

So if you want a api to get token depend on username and password will look like this:

def get_token(request):
    username = request.POST.get("username")
    password = request.POST.get("password")
    .... # other parameters
    try:
        user = User.objects.get(username=username, password=password)
    except ObjectDoesNotExist:
        return HttpResponse("Can't find this user")
    else:
        try:
            access_token = AccessToken.objects.get(user=user)
        except ObjectDoesNotExist:
            return HttpResponse("Haven't set any token")
        else:
            return HttpResponse(access_token)

If you want to use DRF to handle this:

@api_view(['POST'])
def get_token(request):
    # get token by query just like above
    serializer = TokenSerializer(data=access_token.token) #you can pass more parameters to data if you want, but you also have to edit your TokenSerializer
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Your TokenSerializer:

class TokenSerializer(ModelSerializer):
    class Meta:
        model = AccessToken
        field = (token,)

EDIT

It depends

  • Web, you post your username and password to login api, your browser store session in your cookies.
  • Mobile, you post your username and password to login api, server response the token then you store it in your mobile, maybe keychain when you are developing IOS app.And send it as http header when you want to access the server, how-can-i-get-all-the-request-headers-in-django
Windsooon
  • 6,864
  • 4
  • 31
  • 50
  • You have called AccessToken model on UserCreateSerializer. Is my UserCreateSerializer wrong? While registering new user, a new token is created with my current code but i want token to be called while logging in. – Serenity Sep 06 '16 at 03:55
  • https://github.com/Tushant/foodie-rest-api/tree/master/userprofiles . You can see here my user creation is working. When user is created a token is created too. But i could not login with the token as my access_token = AccessToken.objects.get(token=request.data.get('access_token'), expires__gt=timezone.now()) returns None instead of token. It is in UserLoginAPI. – Serenity Sep 06 '16 at 03:59
  • When you login, I guess your token is in your header instead of in your requests body.So you can't find it. – Windsooon Sep 06 '16 at 06:08
  • How to access it then? Could you please help me on this? – Serenity Sep 06 '16 at 06:39
  • i passed the url in form action as
    but i get an error {"error": "unsupported_grant_type"}
    – Serenity Sep 06 '16 at 07:21
  • I edit my answer, and this is another question, but you can have a look at https://stackoverflow.com/questions/35861583/sage-one-api-unsupported-grant-type – Windsooon Sep 06 '16 at 08:16
  • So i need to pass all those client id , client secret and grant_type from frontend. – Serenity Sep 06 '16 at 08:19
  • If i want to user your code for login then i have to define the field username and password in TokenSerializer ? That way it will show username and password field for log in page . – Serenity Sep 06 '16 at 08:37
  • write_only field for token? – Serenity Sep 06 '16 at 09:10
  • for username and password if you don't want them show on your api page – Windsooon Sep 06 '16 at 09:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/122724/discussion-between-learner-and-aison). – Serenity Sep 06 '16 at 09:31