Django rest framework: Obtain auth token using email instead username

前端 未结 4 1735
有刺的猬
有刺的猬 2020-12-24 08:39

I\'m working on a project to enable the django rest framework authentication for mobile devices. I\'m using the default token authentication for get the user token from a po

相关标签:
4条回答
  • 2020-12-24 09:21

    Ok,I found a way for get the auth token using email or username... This is the serializer:

    class AuthCustomTokenSerializer(serializers.Serializer):
        email_or_username = serializers.CharField()
        password = serializers.CharField()
    
        def validate(self, attrs):
            email_or_username = attrs.get('email_or_username')
            password = attrs.get('password')
    
            if email_or_username and password:
                # Check if user sent email
                if validateEmail(email_or_username):
                    user_request = get_object_or_404(
                        User,
                        email=email_or_username,
                    )
    
                    email_or_username = user_request.username
    
                user = authenticate(username=email_or_username, password=password)
    
                if user:
                    if not user.is_active:
                        msg = _('User account is disabled.')
                        raise exceptions.ValidationError(msg)
                else:
                    msg = _('Unable to log in with provided credentials.')
                    raise exceptions.ValidationError(msg)
            else:
                msg = _('Must include "email or username" and "password"')
                raise exceptions.ValidationError(msg)
    
            attrs['user'] = user
            return attrs
    

    In the email_or_username field, the user can send the email or the username, and using the function validateEmail(), we can check if the user is trying to login using email or username. Then, we can make the query for get the user instance if is valid, and authenticate it.

    This is the view.

    class ObtainAuthToken(APIView):
        throttle_classes = ()
        permission_classes = ()
        parser_classes = (
            parsers.FormParser,
            parsers.MultiPartParser,
            parsers.JSONParser,
        )
    
        renderer_classes = (renderers.JSONRenderer,)
    
        def post(self, request):
            serializer = AuthCustomTokenSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            user = serializer.validated_data['user']
            token, created = Token.objects.get_or_create(user=user)
    
            content = {
                'token': unicode(token.key),
            }
    
            return Response(content)
    

    and then:

    curl --data "email_or_username=emailorusername&password=password" http://127.0.0.1:8000/api/my-api-token-auth/.
    

    It's ready.

    0 讨论(0)
  • 2020-12-24 09:25

    Write these requirements into your settings.py

    ACCOUNT_AUTHENTICATION_METHOD = 'email'
    ACCOUNT_EMAIL_REQUIRED = True
    ACCOUNT_USERNAME_REQUIRED = False
    

    To check, send this json format request to your server:

    {
        "username":"youremail@mail.domain",
        "password":"Pa$$w0rd"
    }
    
    0 讨论(0)
  • 2020-12-24 09:27

    There is a cleaner way to get the user token.

    simply run manage.py shell

    and then

    from rest_framework.authtoken.models import Token
    from django.contrib.auth.models import User
    u = User.objects.get(username='admin')
    token = Token.objects.create(user=u)
    print token.key
    
    0 讨论(0)
  • 2020-12-24 09:28

    Change the default serializer the library is using for example in auth/serializers.py

    from django.contrib.auth import authenticate
    from django.utils.translation import gettext_lazy as _
    
    from rest_framework import serializers
    
    
    class MyAuthTokenSerializer(serializers.Serializer):
        email = serializers.EmailField(label=_("Email"))
        password = serializers.CharField(
            label=_("Password",),
            style={'input_type': 'password'},
            trim_whitespace=False
        )
    
        def validate(self, attrs):
            email = attrs.get('email')
            password = attrs.get('password')
    
            if email and password:
                user = authenticate(request=self.context.get('request'),
                                    email=email, password=password)
    
                # The authenticate call simply returns None for is_active=False
                # users. (Assuming the default ModelBackend authentication
                # backend.)
                if not user:
                    msg = _('Unable to log in with provided credentials.')
                    raise serializers.ValidationError(msg, code='authorization')
            else:
                msg = _('Must include "username" and "password".')
                raise serializers.ValidationError(msg, code='authorization')
    
            attrs['user'] = user
            return attrs
    

    Override the view for example in auth/views.py

    from rest_framework.authtoken import views as auth_views
    from rest_framework.compat import coreapi, coreschema
    from rest_framework.schemas import ManualSchema
    
    from .serializers import MyAuthTokenSerializer
    
    
    class MyAuthToken(auth_views.ObtainAuthToken):
        serializer_class = MyAuthTokenSerializer
        if coreapi is not None and coreschema is not None:
            schema = ManualSchema(
                fields=[
                    coreapi.Field(
                        name="email",
                        required=True,
                        location='form',
                        schema=coreschema.String(
                            title="Email",
                            description="Valid email for authentication",
                        ),
                    ),
                    coreapi.Field(
                        name="password",
                        required=True,
                        location='form',
                        schema=coreschema.String(
                            title="Password",
                            description="Valid password for authentication",
                        ),
                    ),
                ],
                encoding="application/json",
            )
    
    
    obtain_auth_token = MyAuthToken.as_view()
    

    Hook up the url for example in auth/urls.py

    from .views import obtain_auth_token
    urlpatterns = [
        re_path(r'^api-token-auth/', obtain_auth_token),
    ]
    

    and you are ready to go!!

    0 讨论(0)
提交回复
热议问题