Django Rest Framework 自定义身份验证 + 基本身份验证

Django Rest Framework Custom authentication + Basic Auth

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

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

 @authentication_classes((CustomAuthentication,  ))

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

@authentication_classes((SessionAuthentication, BasicAuthentication, CustomAuthentication ))

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

Django Rest Framework 认证 documentation 明确指出:

The authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set request.user and request.auth using the return value of the first class that successfully authenticates.

If no class authenticates, request.user will be set to an instance of django.contrib.auth.models.AnonymousUser, and request.auth will be set to None.

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

如果您想通过 CustomAuthentication class return NoneBasicAuthentication 进行身份验证,这样您的所有身份验证 class 都会被使用,但用户根据您的 CustomAuthentication

设置

@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)