2015-09-22 39 views
0

我使用Django Rest Framework 3.2.3(DRF)和Django Rest Framework JWT 1.7.2(DRF-JWT,https://github.com/GetBlimp/django-rest-framework-jwt)創建登錄標記。Django Rest Framework中的ValidationError JWT不使用自定義異常處理程序

當從400到202發佈JWT時,我需要更改無效憑據的狀態代碼(僅供參考,我的客戶端無法讀取非200響應的主體)。我使用自定義異常處理程序,通過Django的REST框架描述來實現它: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個「錯誤請求」響應代碼。

與其他每個DRF接口一樣,我按預期獲得了202狀態碼。

我該如何獲得DRF-JWT的ValidationErrors自定義異常處理程序?

+0

如果'提高ValidationError(MSG)'在視圖中被使用時,定製異常處理程序exceutes。如果在序列化程序中使用'raise ValidationError(msg)',那麼自定義異常處理程序不會**被使用。有沒有辦法以某種方式擴展DRF-JWT? – Rias

回答

2

爲什麼我們無法在這裏使用自定義異常處理程序?

發生這種情況是因爲raise_exception標記在調用.is_valid()時尚未傳遞給JSONWebTokenSerializer。 (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代碼。

由於每DRF節上Raising an exception on invalid data:

.is_valid()方法有一個可選的raise_exception標誌 將導致它提出一個serializers.ValidationError異常如果 有驗證錯誤。

這些異常會自動由REST框架提供的默認異常 處理程序處理,並且將返回HTTP 400錯誤 默認情況下請求響應。

SOLUTION:

如果你調用.is_valid()功能時傳遞raise_exception標誌作爲True,爲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()) 
+0

我在文檔中發現這個句子容易讓人誤解,我的印象是,只有當我直接用HTTP_400_BAD_REQUEST修改響應時,纔會使用異常處理程序。 無論如何,我如何在DRF-JWT中使用400錯誤的異常處理程序? – Rias

+0

我甚至不認爲,這是適當的。如果我在自定義視圖中引發ValidationError'raise ValidationError('Invalid data。')'我仍然得到預期的202狀態碼。儘管如果ValidationError在JWT中引發(https://github.com/GetBlimp/django-rest-framework-jwt/blob/master/rest_framework_jwt/serializers.py#L66-L67),它不會返回202. – Rias

+0

發生這種情況是因爲在調用'.is_valid()'時'raise_exception'標誌沒有被傳遞給'JSONWebTokenSerializer'。如果我們傳遞這個參數,那麼將使用自定義異常處理程序。更新了ans。 –

0

我想,也許一個更清潔的方式做到這一點不涉及重寫後的方法是

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'), 
] 
相關問題