Django身份验证功能尝试绑定到自定义身份验证功能时发生TypeError

问题描述

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

请注意,这不适用于任何关键任务生产软件-我正在阅读《服从测试山羊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('/')

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

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,因此未调用我的自定义auth函数。 (我已经通过打印语句确认了这一点)

这里是AUTHENTICATION_BACKENDS中的settings.py_get_backends语句中的for函数将查找此设置,以确定应使用哪种身份验证后端。我可以确认它找到了我的自定义后端-由于某种原因,传入的参数无法绑定到它:

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)

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

解决方法

想通了。

我的身份验证功能需要带一个请求参数,因为默认情况下为None的请求参数是从Django authenticate函数中层叠下来的。

所以我的自定义身份验证功能签名看起来像这样:

authenticate(self,request,uid)