5

My goal is to override obtain_jwt_token in order to get more control over the return value of the procedure, and in the doc I found only a bizarre and sketchy info on how to do this:

Note that the default obtain_auth_token view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. If you need a customized version of the obtain_auth_token view, you can do so by overriding the ObtainAuthToken view class, and using that in your url conf instead

As for now, my attempt looks like this:

urlpatterns = [
   url(r'^api-token-auth/', my_customized_view),
]

class Foo(ObtainAuthToken):
    def post(self):
       # here goes my customized code

my_customized_view = Foo.as_view()

The odds are that my code looks quite silly, and I am just lost trying to google it. I have little experience in Djagno, so please help me with this !

Crazy Frog
  • 495
  • 8
  • 17
  • I don't understand exactly what you are trying to do. Maybe if you had a better example of your goals and actual code. For JWT I use http://getblimp.github.io/django-rest-framework-jwt/ which works fine and is very easy to customize the jwt response. – E. Celis Feb 20 '17 at 16:40
  • If I am right, you are trying to customize returning a token based on some criteria. Random Guess. – Divij Sehgal Apr 16 '17 at 16:37

2 Answers2

6

I have just been going through the same journey for comprehension as I wished to return the user and also allow email or username login. The documentation is not entirely clear, but as described for auth token, you can do the same for JWT. obtain_auth_token is to ObtainAuthToken, as obtain_jwt_token is to ObtainJSONWebToken. This is my overwritten login method:

from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.views import ObtainJSONWebToken

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER


class LoginView(ObtainJSONWebToken):
    def post(self, request, *args, **kwargs):
        # by default attempts username / passsword combination
        response = super(LoginView, self).post(request, *args, **kwargs)
        # token = response.data['token']  # don't use this to prevent errors
        # below will return null, but not an error, if not found :)
        res = response.data
        token = res.get('token')

        # token ok, get user
        if token:
            user = jwt_decode_handler(token)  # aleady json - don't serialize
        else:  # if none, try auth by email
            req = request.data  # try and find email in request
            email = req.get('email')
            password = req.get('password')
            username = req.get('username')

            if email is None or password is None:
                return Response({'success': False, 
                                'message': 'Missing or incorrect credentials',
                                'data': req},
                                status=status.HTTP_400_BAD_REQUEST)

            # email exists in request, try to find user
            try:
                user = User.objects.get(email=email)
            except:
                return Response({'success': False, 
                                'message': 'User not found',
                                'data': req},
                                status=status.HTTP_404_NOT_FOUND)

            if not user.check_password(password):
                return Response({'success': False, 
                                'message': 'Incorrect password',
                                'data': req},
                                status=status.HTTP_403_FORBIDDEN)

            # make token from user found by email
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            user = UserSerializer(user).data

        return Response({'success': True,
                        'message': 'Successfully logged in',
                        'token': token,
                        'user': user}, 
                        status=status.HTTP_200_OK)

You can change the default to check by email only if you please by customising Django's auth model, but I was happy to have both options.

I started creating an api boilerplate. There is a requirements.txt file and a config.example.py file for anyone who wants to pull it down to view the rest. https://github.com/garyburgmann/django-api-boilerplate

Sreekar Mouli
  • 1,313
  • 5
  • 25
  • 49
Gary Burgmann
  • 193
  • 2
  • 5
0
  1. In views.py, file add the following code and customize as you want.
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'user': UserSerializer(user, context={'request': request}).data
    }

Default is {'token': token}

  1. Also In your settings.py file add
JWT_AUTH = {
    
    'JWT_RESPONSE_PAYLOAD_HANDLER':
        'api.user.views.jwt_response_payload_handler',
 }

( 'api.user.views.jwt_response_payload_handler', ) is the path to your custom jwt_response_payload_handler

For more help, you can view here