【问题标题】:Django rest framework: Obtain auth token using email instead usernameDjango rest框架:使用电子邮件而不是用户名获取身份验证令牌
【发布时间】:2015-03-19 10:44:30
【问题描述】:

我正在开发一个为移动设备启用 django rest 框架身份验证的项目。我正在使用默认令牌身份验证从发送用户名和密码的发布请求中获取用户令牌。

curl --data "username=username&password=password" http://127.0.0.1:8000/api/api-token-auth/

(api/api-token-auth/ 为获取auth_token视图配置的url)

urlpatterns = [
    url(r'^api/api-token-auth/', obtain_auth_token),
    url(r'^', include(router.urls)),
]

响应是用户令牌。

{"token":"c8a8777aca969ea3a164967ec3bb341a3495d234"}

我需要在帖子上使用电子邮件密码而不是用户名密码来获取用户令牌身份验证,或者两者都使用。我正在阅读自定义身份验证的文档http://www.django-rest-framework.org/api-guide/authentication/#custom-authentication... 但实际上,对我来说不是很清楚。 这对我很有帮助...谢谢:)。

【问题讨论】:

  • 您的应用是否已经可以使用电子邮件和密码登录?或者这是您为应用实施的第一种身份验证方法?
  • 嗨...是第一种身份验证方法,我之前没有实现过其他...现在我使用默认的获取令牌方法,使用用户名和密码...但是,在移动设备中,我需要使用电子邮件和密码获取令牌身份验证。

标签: django authentication django-rest-framework


【解决方案1】:

更改库使用的默认序列化程序,例如在 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

覆盖视图,例如 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()

例如在 auth/urls.py

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

你准备好了!

【讨论】:

    【解决方案2】:

    将这些要求写入您的 settings.py

    ACCOUNT_AUTHENTICATION_METHOD = 'email'
    ACCOUNT_EMAIL_REQUIRED = True
    ACCOUNT_USERNAME_REQUIRED = False
    

    要检查,请将此 json 格式请求发送到您的服务器:

    {
        "username":"youremail@mail.domain",
        "password":"Pa$$w0rd"
    }
    

    【讨论】:

    • 是 DRF 设置还是设置的全局部分。
    • 我发现发送 json 并使用字段“用户名”但值是电子邮件,仍然有效。无需在 settings.py 中添加 ACCOUNT_。
    • 这似乎来自 django-allauth,而不是 drf
    【解决方案3】:

    有一种更简洁的方式来获取用户令牌。

    只需运行 manage.py shell

    然后

    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
    

    【讨论】:

    • 对 django
    • 这是一种获取令牌的方法,但这不是OP的问题。
    • 我认为,这比这要好得多。附言你可以添加 CSRF 令牌。
    【解决方案4】:

    好的,我找到了一种使用电子邮件或用户名获取身份验证令牌的方法...这是序列化程序:

    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
    

    在 email_or_username 字段中,用户可以发送电子邮件或用户名,使用函数validateEmail(),我们可以检查用户是否尝试使用电子邮件或用户名登录。然后,我们可以查询获取用户实例是否有效,并对其进行身份验证。

    这是视图。

    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)
    

    然后:

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

    准备好了。

    【讨论】:

    • 您好!我尝试了您的解决方案,但它抱怨缺少方法 validateEmail 和 authenticate 。你能分享一下丢失的代码吗?谢谢!
    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 2016-12-16
    • 2017-12-04
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 2018-12-15
    • 2016-07-26
    相关资源
    最近更新 更多