我使用的是自定义身份验证方案,我无法弄清楚如何让它发送401 HTTP响应而不是403. http://www.django-rest-framework.org/api-guide/authentication/#custom-authentication上的指南说要覆盖authenticate_header方法,但这并不是&# 39;似乎什么也做不了。发送403的部分是引发AuthenticationFailed异常的地方。我通过permission_classes属性将OwnerCredentialsFound分配给了ModelViewSet。
from rest_framework import exceptions
from rest_framework import permissions
from django.contrib.auth.models import User
def authenticateUser(username, password):
try:
user = User.objects.get(username=username)
return user.check_password(password)
except:
return False
class OwnerCredentialsFound(permissions.IsAuthenticated):
def has_permission(self, request, view):
#Check credentials
#If the fields don't exist, the given default value is used
username = request.POST.get('username', None)
password = request.POST.get('password', None)
authenticated = authenticateUser(username, password)
if(not authenticated and username is not None and password is not None):
raise exceptions.AuthenticationFailed('Username/password pair not found')
elif(not authenticated):
authenticated = permissions.IsAuthenticated.has_permission(self, request, view)
else:
#set the user
view.request.user = User.objects.get(username=username)
return authenticated
def authenticate_header(self, request):
return '{"username" : <username>, "password" : <password>}'
更新:似乎我已经混淆了身份验证和权限类。我使用的是权限类,但是它的身份验证类有一个名为authenticate_header的方法。
答案 0 :(得分:2)
当您从False
返回has_permission
时,DRF会引发PermissionDenied
异常。然后在名为exception_hanlder
的函数中捕获并处理异常,如下所示:
elif isinstance(exc, PermissionDenied):
msg = _('Permission denied.')
data = {'detail': six.text_type(msg)}
set_rollback()
return Response(data, status=status.HTTP_403_FORBIDDEN)
看起来您可以定义一些自定义异常,在OwnerCredentialsFound.has_permission
中将其抛出错误,然后使用自定义异常处理程序自己捕获它。请在这里阅读更多:
http://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
答案 1 :(得分:1)
基本上,我并没有真正了解权限和身份验证之间的区别,因此导致了混淆。权限类没有authenticate_header方法,但身份验证类具有。以下是我为解决问题所做的工作:
from rest_framework import exceptions
from rest_framework import authentication
from django.contrib.auth.models import User
def authenticateUser(username, password):
try:
user = User.objects.get(username=username)
return user.check_password(password)
except:
return False
class CustomAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.POST.get('username', None)
password = request.POST.get('password', None)
authenticated = authenticateUser(username, password)
if(not authenticated and username is not None and password is not None):
#authentication attempted and failed
raise exceptions.AuthenticationFailed('Username/password pair not found')
elif(not authenticated):
#authentication not attempted (try other authentications)
return None
else:
#authentication attempted and suceeded
return (User.objects.get(username=username), None)
def authenticate_header(self, request):
return '{"username" : <username>, "password" : <password>}'
在我看来:
permission_classes = (IsAuthenticated,)
authentication_classes = (CustomAuthentication, SessionAuthentication)
这种权限和身份验证的混淆也解释了为什么我尝试组合多个权限类失败(您可能会在我的原始代码中注意到我从权限类继承并调用其has_permission方法以解决此问题)。我不再需要自定义权限类,因为我可以使用两个身份验证类。