【问题标题】:Django Rest Framework Custom authentication + Basic AuthDjango Rest Framework 自定义身份验证 + 基本身份验证
【发布时间】:2015-11-12 11:07:53
【问题描述】:

我在我的 Python-Django 应用程序中使用 Django Rest Framework,并为 api 使用自定义身份验证。

如果我只使用我的自定义身份验证方法,则可以正常工作。

 @authentication_classes((CustomAuthentication,  ))

但是,如果我尝试按顺序进行基本身份验证和自定义身份验证,我的自定义身份验证永远不会执行。我的意思是,如果基本身份验证失败,我希望尝试使用自定义身份验证。基本认证执行然后结束。

@authentication_classes((SessionAuthentication, BasicAuthentication, CustomAuthentication ))

是否可以同时拥有这三种认证方式,并按顺序执行?

【问题讨论】:

    标签: django authentication django-rest-framework custom-authentication


    【解决方案1】:

    @Arpit Goyal 的回答让工作流程变得清晰。

    如果您确实想通过所有身份验证类,

    这里有一个变通方法,您可以尝试一下。希望对你有帮助。

    @authentication_classes((AuthencationWrapper,  ))
    

    添加AuthencationWrapper

    class AuthencationWrapper(BaseAuthentication):
    
        authenication_classes = (
            BasicAuthentication,
            SessionAuthentication,
            CustomAuthentication,
        )
    
        def authenticate(self, request):
            exc = None
            ret = None
            for auth in self.authentication_classes:
                try:
                    ret = auth().authenticate(request)
                    # if success, we will break, else we will continue to call next one
                    break
                except exceptions.AuthenticationFailed as e:
                    # we only record the first failed exception
                    if exc is None:
                        exc = e
                        self.first_failed_auth = auth()
            if ret is None:
                raise exc
    
            # one of the authentication_classes is passed
            return ret
    
        def authenticate_header(self, request):
            # actualy this way breaks what django-rest-framework doing now
            return self.first_failed_auth.authenticate_header(request)
    
            # the one follows what django-rest-framework doing now
            # choose the first authentication class header
            ## if self.authentication_classes:
            ##      return self.authentication_classes[0].authenticate_header(request)
    

    【讨论】:

    • 出现该错误AttributeError: 'WSGIRequest' object has no attribute 'successful_authenticator 。找到那个问题,但似乎不一样:stacklink
    • 如果您的CustomAuthentication 失败,您会引发exceptions.AuthenticationFailed 错误吗?
    • 尝试使用authenication_classes = ( BasicAuthentication, SessionAuthentication ) 并遇到同样的错误。
    • 已解决,似乎ret = auth().authenticate(request)没有正确实例化该类,必须换行。
    【解决方案2】:

    Django Rest Framework 身份验证documentation 明确说明了这一点:

    身份验证方案始终定义为类列表。 REST 框架将尝试对 列表,并将使用返回设置 request.user 和 request.auth 成功验证的第一个类的值。

    如果没有类通过身份验证,request.user 将被设置为 django.contrib.auth.models.AnonymousUser 和 request.auth 将被设置 到无。

    因此,每当您的第一个类验证 request.user 并设置 request.auth 时。

    如果您想使用您的 CustomAuthenticationreturn NoneBasicAuthentication 进行身份验证,以便使用您的所有身份验证类,但用户是根据您的 CustomAuthentication 设置的

    【讨论】:

    • 如果第一个认证类失败,它会抛出一个异常,所以永远不会到达第二个认证类。
    • 考虑到@soooooot 这里的输入是说明django rest框架在未经授权或被禁止响应的情况下的身份验证的文档。