我正在使用Django Rest Framework 3.2.3(DRF)和Django Rest Framework JWT 1.7.2(DRF-JWT,https://github.com/GetBlimp/django-rest-framework-jwt)来创建登录令牌。
我需要在从400到202发布JWT时更改无效凭据的状态代码(仅供参考:我的客户端无法读取非200响应的正文)。我使用Django Rest Framework描述的自定义异常处理程序来实现它:http://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling
RESTAPI / custom_exception.py
from rest_framework.views import exception_handler
from rest_framework import status
def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
print ('Exception raised: ' + str(response.status_code))
# Now add the HTTP status code to the response.
if response is not None:
if response.status_code != status.HTTP_403_FORBIDDEN:
response.status_code = status.HTTP_202_ACCEPTED
return response
在配置中:
'EXCEPTION_HANDLER': 'restapi.custom_exception.custom_exception_handler',
当使用无效凭据时,DRF-JWT应引发ValidationError。在向JWT token-auth接口发布无效凭据时,我仍然收到400 Bad Request响应代码。
对于每个其他DRF接口,我按预期获得202状态代码。
如何让DRF-JWT为其ValidationErrors使用自定义异常处理程序?
答案 0 :(得分:3)
为什么我们无法在此处使用自定义异常处理程序?
这种情况正在发生,因为raise_exception
标记在调用JSONWebTokenSerializer
时尚未传递给.is_valid()
。 (JSONWebTokenSerializer
是用于验证用户名和密码的序列化程序类。)
post()
方法的DRF-JWT源代码:
def post(self, request):
serializer = self.get_serializer(
data=get_request_data(request)
)
if serializer.is_valid(): # 'raise_exception' flag has not been passed here
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
response_data = jwt_response_payload_handler(token, user, request)
return Response(response_data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
现在,我们可以看到raise_exception
标志尚未传递给is_valid()
。发生这种情况时,不会引发ValidationError
,从而导致您的custom_exception_handler
代码无法执行。
根据Raising an exception on invalid data:
上的DRF部分
.is_valid()
方法采用可选的raise_exception
标记 会导致它引发serializers.ValidationError
例外 有验证错误。这些异常由默认异常自动处理 REST框架提供的处理程序,并将返回HTTP 400 Bad 默认情况下请求回复。
<强> SOLUTION:强>
如果您在调用raise_exception
函数时将True
标记作为.is_valid()
传递,则custom_exception_handler
的代码将被执行。
您需要创建一个CustomObtainJSONWebToken
视图,该视图将从默认的ObtainJSONWebToken
视图继承。在此,我们将覆盖.post()
方法以传递raise_exception
标志。然后将在我们的网址中指定此视图。
<强>程序my_app / views.py 强>
from rest_framework_jwt.views import ObtainJSONWebToken
class CustomObtainJSONWebToken(ObtainJSONWebToken):
def post(self, request):
serializer = self.get_serializer(
data=get_request_data(request)
)
serializer.is_valid(raise_exception=True) # pass the 'raise_exception' flag
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
response_data = jwt_response_payload_handler(token, user, request)
return Response(response_data)
<强> urls.py 强>
# use this view to obtain token
url(r'^api-token-auth/', CustomObtainJSONWebToken.as_view())
答案 1 :(得分:0)
我认为可能采用一种更简洁的方式来覆盖post方法
<强> serializers.py 强>
from rest_framework_jwt import serializers as jwt_serializers
class JSONWebTokenSerializer(jwt_serializers.JSONWebTokenSerializer):
"""
Override rest_framework_jwt's ObtainJSONWebToken serializer to
force it to raise ValidationError exception if validation fails.
"""
def is_valid(self, raise_exception=None):
"""
If raise_exception is unset, set it to True by default
"""
return super().is_valid(
raise_exception=raise_exception if raise_exception is not
None else True)
<强> views.py 强>
from rest_framework_jwt import views as jwt_views
from .serializers import JSONWebTokenSerializer
class ObtainJSONWebToken(jwt_views.ObtainJSONWebToken):
"""
Override the default JWT ObtainJSONWebToken view to use the custom serializer
"""
serializer_class = JSONWebTokenSerializer
<强> urls.py 强>
from django.conf.urls import url
from .views import ObtainJSONWebToken
urlpatterns = [
...
url(r'^api-token-auth/', ObtainJSONWebToken.as_view(), name='jwt-create'),
]