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 None
对 BasicAuthentication
进行身份验证,这样您的所有身份验证 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)
我在 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 None
对 BasicAuthentication
进行身份验证,这样您的所有身份验证 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)