Django Rest使用用户名或电子邮件登录JWT?

时间:2015-12-17 10:20:09

标签: django django-rest-framework jwt

我在我的应用中使用 django-rest-jwt 进行身份验证。

默认情况下,用户用户名字段用于验证用户,但我希望让用户使用电子邮件或用户名进行登录。

django-rest-jwt是否支持完成此任务。 我知道最后一个选项是编写我自己的登录方法。

4 个答案:

答案 0 :(得分:21)

无需编写自定义身份验证后端或自定义登录方法。

继承JSONWebTokenSerializer的自定义序列化程序,重命名' username_field'并覆盖def validate()方法。

这适用于' username_or_email'和密码'用户可以输入其用户名或电子邮件并获取JSONWebToken以获取正确凭据的字段。

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)

在urls.py中:

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

答案 1 :(得分:1)

找到了解决方法。

@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)

我检查收到的文字是用户名还是电子邮件。

如果是电子邮件,那么我会查找该用户名,然后将其传递给/signin_jwt/

答案 2 :(得分:0)

以Shikhar的答案为基础,对于任何来这里寻求 rest_framework_simplejwt 解决方案的人(由于 django-rest-framework-jwt 似乎已经死了,这是最后一个了)像2年前一样提交(commit是2年前),这是一个通用解决方案,它试图尽可能少地更改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)

在urls.py中:

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

答案 3 :(得分:0)

或者,这个新的 DRF 身份验证项目 dj-rest-auth 似乎支持通过用户名或电子邮件通过 djangorestframework-simplejwt 登录。

相关问题