OAuth2:使用电子邮件而非用户名进行身份验证

9
我将使用django-oauth-toolkit和django-rest-framework进行OAuth2认证。
通常,我通过以下方式对用户进行身份验证,以获取令牌:
curl -X POST -d "grant_type=password&username=new_user&password=new_user" -u "GZwzDjPM89BceT8a6ypKGMbXnE4jWSzsyqbM3dlK:" http://localhost:8000/o/token/

是否有一种方法可以使用电子邮件而不是用户名来验证我的用户?

谢谢!

4个回答

5

是的!通过在用户模型中将电子邮件设置为用户名,这是可能的。

class User(AbstractBaseUser, PermissionsMixin):
 email =  models.EmailField(
    verbose_name='email address',
    max_length=255,
    unique=True,
 )
 first_name = models.CharField(max_length=30)
 last_name = models.CharField(max_length=30)

 USERNAME_FIELD = 'email'

现在电子邮件可以用作请求中的用户名

curl -X POST -d "grant_type=password&username=test@test.com&password=new_user" -u "GZwzDjPM89BceT8a6ypKGMbXnE4jWSzsyqbM3dlK:" http://localhost:8000/o/token/

1
Django 1.11 新功能。对我来说有点晚了,但还是很好知道,谢谢! - Michael

4

如果您不想(或无法)创建自定义的用户模型,那么这里有一个简单的解决方案:只需像这样覆盖rest_framework_social_oauth2.views.TokenView

from django.contrib.auth import get_user_model
import rest_framework_social_oauth2.views

class TokenView(rest_framework_social_oauth2.views.TokenView):
    def create_token_response(self, request):
        email = request.POST.pop('email', None)
        if email:
            username = get_user_model().objects.filter(email=email[0]).values_list('username', flat=True).last()
            request.POST['username'] = username
        return super(TokenView, self).create_token_response(request)

然后,在你的urls.conf中将这个定制化的视图与oauth/token模式连接起来,例如:

urlpatterns = [
    url(r'^oauth/token', my_auth.TokenView.as_view()),  # The customized TokenView
    url(r'^oauth/', include('rest_framework_social_oauth2.urls')),  # Original URLs
]

URL 应为 oauth/token/,以覆盖 OAuth2 的默认 URL。 - Anuj TBE

1

我不知道为什么这个问题从来没有得到解答,但无论如何,我希望我的回答对于遇到这个问题的人有所帮助:

丑陋但快速的方法:

将电子邮件作为用户名发送到您的POST请求中,然后找到其真实用户名,并替换您的POST请求为此数据;所有这些都在您的中间件中完成:

class DisableCSRF(object):
    """Middleware for disabling CSRF in a specified app name.
    """

    def process_request(self, request):
        """Preprocess the request.
        """

        if (resolve(request.path_info).app_name == "api") or (
                resolve(request.path_info).namespace == "oauth2_provider"):

            if resolve(request.path_info).namespace == "oauth2_provider":

                post_data = request.POST.copy()

                true_username = User.objects.get(
                    email=request.POST.get("username")
                ).username
                post_data["username"] = true_username
                request.POST = post_data

            setattr(request, '_dont_enforce_csrf_checks', True)
        else:
            pass  # check CSRF token validation

优雅且良好的做法:

创建自己的类来请求认证令牌,以便您可以将电子邮件作为用户名接收。您甚至可以添加更多自定义验证,例如Facebook或Google登录。这绝对是最好的方法,但需要更多时间来开发,因此如果您有足够的时间来实施它,则由您决定。

希望回答得不会太晚。


0
knaperek的答案对我没有起作用。 基于他的代码,我最终得出了以下解决方案,这对我的情况非常有效:
import json
from django.http import HttpResponse
from django.contrib.auth import get_user_model
from oauth2_provider.views.base import TokenView
from oauth2_provider.models import get_access_token_model
from oauth2_provider.signals import app_authorized
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.debug import sensitive_post_parameters
from django.contrib.auth import get_user_model


@method_decorator(csrf_exempt, name="dispatch")
class TokenView(TokenView):
    @method_decorator(sensitive_post_parameters("password"))
    def post(self, request, *args, **kwargs):
        request.POST = request.POST.copy()
        email = request.POST.pop('email', None)
        request.POST['username'] = get_user_model().objects.filter(email=email[0]).values_list('username', flat=True).last()
        url, headers, body, status = self.create_token_response(request)
        if status == 200:
            access_token = json.loads(body).get("access_token")
            if access_token is not None:
                token = get_access_token_model().objects.get(token=access_token)
                app_authorized.send(sender=self, request=request, token=token)
        response = HttpResponse(content=body, status=status)

        for k, v in headers.items():
            response[k] = v
        return response

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接