Login to Django Rest JWT using username or email?

I am using django-rest-jwt for authentication in my application.

By default, this is a username field for user authentication, but I want users to log in using an email address or username .

Is there any average value supported by django-rest-jwt to accomplish this. I know that the last option will be to write my own login method.

+9
source share
3 answers

No need to write a custom authentication backend or login method.

A custom serializer that inherits from the JSONWebTokenSerializer, renames username_field and overrides the def validate () method.

This works great for the username_or_email and password fields, where the user can enter their username or email address and get a JSONWebToken for the correct credentials.

from rest_framework_jwt.serializers import JSONWebTokenSerializer from django.contrib.auth import authenticate, get_user_model from django.utils.translation import ugettext as _ from rest_framework import serializers from rest_framework_jwt.settings import api_settings User = get_user_model() jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER jwt_decode_handler = api_settings.JWT_DECODE_HANDLER jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER class CustomJWTSerializer(JSONWebTokenSerializer): username_field = 'username_or_email' def validate(self, attrs): password = attrs.get("password") user_obj = User.objects.filter(email=attrs.get("username_or_email")).first() or User.objects.filter(username=attrs.get("username_or_email")).first() if user_obj is not None: credentials = { 'username':user_obj.username, 'password': password } if all(credentials.values()): user = authenticate(**credentials) if user: if not user.is_active: msg = _('User account is disabled.') raise serializers.ValidationError(msg) payload = jwt_payload_handler(user) return { 'token': jwt_encode_handler(payload), 'user': user } else: msg = _('Unable to log in with provided credentials.') raise serializers.ValidationError(msg) else: msg = _('Must include "{username_field}" and "password".') msg = msg.format(username_field=self.username_field) raise serializers.ValidationError(msg) else: msg = _('Account with this email/username does not exists') raise serializers.ValidationError(msg) 

In urls.py:

 url(r'{Your url name}$', ObtainJSONWebToken.as_view(serializer_class=CustomJWTSerializer)), 
+20
source

Workaround detected.

 @permission_classes((permissions.AllowAny,)) def signin_jwt_wrapped(request, *args, **kwargs): request_data = request.data host = request.get_host() username_or_email = request_data['username'] if isEmail(username_or_email): # get the username for this email by model lookup username = Profile.get_username_from_email(username_or_email) if username is None: response_text = {"non_field_errors":["Unable to login with provided credentials."]} return JSONResponse(response_text, status=status.HTTP_400_BAD_REQUEST) else: username = username_or_email data = {'username': username, 'password':request_data['password']} headers = {'content-type': 'application/json'} url = 'http://' + host + '/user/signin_jwt/' response = requests.post(url,data=dumps(data), headers=headers) return JSONResponse(loads(response.text), status=response.status_code) 

I check if the text I received is a username or email.

If after this email I search for a username for this and then just pass this /signin_jwt/

+1
source

Based on Shihara's answer, and for everyone who comes here, is looking for a solution for rest_framework_simplejwt (since django-rest-framework-jwt seems dead, the last commit was 2 years ago), like me, here is a general solution that is trying to change as much as possible less initial check from TokenObtainPairSerializer :

 from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class CustomJWTSerializer(TokenObtainPairSerializer): def validate(self, attrs): credentials = { 'username': '', 'password': attrs.get("password") } # This is answering the original question, but do whatever you need here. # For example in my case I had to check a different model that stores more user info # But in the end, you should obtain the username to continue. user_obj = User.objects.filter(email=attrs.get("username")).first() or User.objects.filter(username=attrs.get("username")).first() if user_obj: credentials['username'] = user_obj.username return super().validate(credentials) 

And in urls.py:

url(r'^token/$', TokenObtainPairView.as_view(serializer_class=CustomJWTSerializer)),

0
source

Source: https://habr.com/ru/post/1238510/


All Articles