【问题标题】:TypeError when Django authenticate function tries to bind to custom authenticate function当 Django 身份验证函数尝试绑定到自定义身份验证函数时出现 TypeError
【发布时间】:2021-01-01 12:45:42
【问题描述】:

我正在尝试实现一种身份验证方法,其中:

  • 用户提交他们的电子邮件
  • 我为存储在数据库中的该用户生成一个令牌,或者如果令牌已经存在,我将检索它
  • 我生成一个用于登录的链接并将其通过电子邮件发送给用户,并将令牌作为 HTTP 参数
  • 从链接中提取令牌并用于搜索活跃用户
  • 用户信息被传递到模板

请注意,这不适用于任何关键任务生产软件 - 我正在阅读 Obey The Testing Goat O'Reilly 这本书,这是作者让我们实施的身份验证方法。

所以当用户点击他们电子邮件中的链接时,处理它的视图函数是:

from django.contrib.auth import authenticate, login

def login(request):
    uid = request.GET.get('uid')
    user = authenticate(uid=uid)
    if user is not None:
        login(request, user)
    return redirect('/')

在该视图函数中,我们调用django.contrib.auth 提供的authenticate 函数。这是那个函数:

def authenticate(request=None, **credentials):
    """
    If the given credentials are valid, return a User object.
    """
    for backend, backend_path in _get_backends(return_tuples=True):
        backend_signature = inspect.signature(backend.authenticate)
        try:
            backend_signature.bind(request, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
            
            ### I have confirmed that the bind function above, and specifically the _bind private function, 
            ### is throwing the TypeError so my custom auth function is never getting called
            
            continue
        try:
            user = backend.authenticate(request, **credentials)
        except PermissionDenied:
            # This backend says to stop in our tracks - this user should not be allowed in at all.
            break
        if user is None:
            continue
        # Annotate the user object with the path of the backend.
        user.backend = backend_path
        return user

请注意,这是 Django 框架代码——不是我写的。出于某种原因,backend_signature.bind(request, **credentials) 行抛出了TypeError,所以我的自定义身份验证函数没有被调用。 (我已经通过打印声明确认了这一点)

这是来自settings.pyAUTHENTICATION_BACKENDSfor 语句中的 _get_backends 函数查找此设置以确定应该使用什么身份验证后端。我可以确认它找到了我的自定义后端——由于某种原因,传入的参数无法绑定到它:

AUTHENTICATION_BACKENDS = [
    'accounts.authentication.PasswordlessAuthenticationBackend',
]

这是实际的自定义后端代码:

    def authenticate(self, uid):
        if not Token.objects.filter(uid=uid).exists():
            return None
        token = Token.objects.get(uid=uid)
        try:
            user = ListUser.objects.get(email=token.email)
            return user
        except ListUser.DoesNotExist:
            return ListUser.objects.create(email=token.email)

提前感谢您的帮助 - 如果我可以提供更多信息,请告诉我。

【问题讨论】:

    标签: python django authentication django-authentication


    【解决方案1】:

    想通了。

    我的身份验证函数需要一个请求参数,因为默认为 None 的请求参数是从 Django authenticate 函数级联下来的。

    所以我的自定义身份验证函数签名如下所示:

    authenticate(self, request, uid)
    

    【讨论】:

      猜你喜欢
      • 2019-07-02
      • 2020-04-01
      • 2022-12-10
      • 2016-11-07
      • 1970-01-01
      • 1970-01-01
      • 2015-11-12
      • 1970-01-01
      • 2018-09-26
      相关资源
      最近更新 更多