Django Rest Frameworkに関する回答があることは知っていますが、問題の解決策が見つかりませんでした。
認証といくつかの機能を備えたアプリケーションがあります。 Django Rest Frameworkを使用する新しいアプリを追加しました。このアプリでのみライブラリを使用したい。また、POSTリクエストをしたいのですが、常にこのレスポンスを受け取ります:
{
"detail": "CSRF Failed: CSRF token missing or incorrect."
}
私は次のコードを持っています:
# urls.py
from Django.conf.urls import patterns, url
urlpatterns = patterns(
'api.views',
url(r'^object/$', views.Object.as_view()),
)
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from Django.views.decorators.csrf import csrf_exempt
class Object(APIView):
@csrf_exempt
def post(self, request, format=None):
return Response({'received data': request.data})
現在のアプリケーションに影響を与えずにAPIを追加したい。私の質問は、このアプリでのみCSRFを無効にするにはどうすればよいですか?
このエラーが発生する理由
これは、DRFで使用されるデフォルトのSessionAuthentication
スキームが原因で発生しています。 DRFのSessionAuthentication
は、CSRFをチェックする必要がある認証にDjangoのセッションフレームワークを使用します。
ビュー/ビューセットでauthentication_classes
を定義しない場合、DRFはこの認証クラスをデフォルトとして使用します。
'DEFAULT_AUTHENTICATION_CLASSES'= (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
),
DRFは、同じビューに対するセッションベース認証と非セッションベース認証の両方をサポートする必要があるため、認証されたユーザーのみにCSRFチェックを強制します。これは、認証されたリクエストのみがCSRFトークンを必要とし、匿名リクエストはCSRFトークンなしで送信できることを意味します。
SessionAuthenticationでAJAXスタイルのAPIを使用している場合、PUT, PATCH, POST or DELETE
要求などの「安全でない」HTTPメソッド呼び出しに有効なCSRFトークンを含める必要があります。
その後どうするか
Csrfチェックを無効にするために、デフォルトのCsrfExemptSessionAuthentication
クラスから拡張するカスタム認証クラスSessionAuthentication
を作成できます。この認証クラスでは、実際のSessionAuthentication
内で発生したenforce_csrf()
チェックをオーバーライドします。
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # To not perform the csrf check previously happening
ビューで、authentication_classes
を次のように定義できます。
authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
これでcsrfエラーが処理されるはずです。
より簡単なソリューション:
Views.pyで、中括弧CsrfExemptMixinおよびauthentication_classesを使用します。
# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from Django.views.decorators.csrf import csrf_exempt
from braces.views import CsrfExemptMixin
class Object(CsrfExemptMixin, APIView):
authentication_classes = []
def post(self, request, format=None):
return Response({'received data': request.data})
Urls.pyを変更します
Urls.pyでルートを管理する場合は、csrf_exempt()で目的のルートをラップして、CSRF検証ミドルウェアから除外できます。
from Django.conf.urls import patterns, url
from Django.views.decorators.csrf import csrf_exempt
import views
urlpatterns = patterns('',
url(r'^object/$', csrf_exempt(views.ObjectView.as_view())),
...
)
あるいは、デコレータとして、@ csrf_exemptデコレータの使用が自分のニーズにより適している場合があります
例えば、
from Django.views.decorators.csrf import csrf_exempt
from Django.http import HttpResponse
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
ジョブが完了します!
セッションベースの認証を使用したくない場合は、REST_AUTHENTICATION_CLASSESからSession Authentication
を削除できます。これにより、すべてのcsrfベースの問題が自動的に削除されます。ただし、その場合、Browseable APIは機能しない可能性があります。
さらに、このエラーはセッション認証でも発生しないはずです。 APIにはTokenAuthenticationなどのカスタム認証を使用し、認証トークンとともにリクエストでAccept:application/json
およびContent-Type:application/json
(jsonを使用している場合)を送信するようにしてください。
役に立つ答えを見つけられなかったすべての人に。はい。たとえば、SessionAuthentication
AUTHENTICATION CLASSを使用しない場合、DRFはCSRF保護を自動的に削除します。たとえば、多くの開発者はJWTのみを使用します。
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
ただし、別の理由からCSRF not set
の問題が発生する場合があります。たとえば、表示するパスを正しく追加していません。
url(r'^api/signup/', CreateUserView), # <= error! DRF cant remove CSRF because it is not as_view that does it!
の代わりに
url(r'^api/signup/', CreateUserView.as_view()),
私は同じ問題に見舞われています。私はこれに従いました 参照 そしてそれは働きました。解決策はミドルウェアを作成することです
Disable.pyファイルをアプリの1つに追加します(私の場合は「myapp」です)
class DisableCSRF(object):
def process_request(self, request):
setattr(request, '_dont_enforce_csrf_checks', True)
そして、middilewareをMIDDLEWARE_CLASSESに追加します
MIDDLEWARE_CLASSES = (
myapp.disable.DisableCSRF,
)
アプリケーションに排他的な仮想環境を使用している場合、他のアプリケーションを効果的に使用せずに次のアプローチを使用できます。
rest_framework/authentication.py
がauthenticate
クラスのSessionAuthentication
メソッドにこのコードを持っているため、あなたが観察したことが起こります:
self.enforce_csrf(request)
Request
クラスを変更して、csrf_exempt
という名前のプロパティを作成し、CSRFチェックが必要ない場合は、それぞれのViewクラス内でTrue
に初期化できます。例えば:
次に、上記のコードを次のように変更します。
if not request.csrf_exempt:
self.enforce_csrf(request)
Request
クラスで行う必要がある関連する変更がいくつかあります。完全な実装はここで利用可能です(完全な説明付き): https://github.com/piaxis/Django-rest-framework/commit/1bdb872bac5345202e2f58728d0e7fad70dfd7ed
上記の回答のいくつかを試してみましたが、別のクラスを作成することは少し面倒だと感じました。
参考までに、ユーザー登録のために関数ベースのビューメソッドをクラスベースのビューメソッドに更新しようとしたときに、この問題に遭遇しました。
クラスベースビュー(CBV)およびDjango Rest Framework(DRF)を使用する場合、ApiViewクラスから継承し、permission_classesおよびauthentication_classesを空のTupleに設定します。以下の例をご覧ください。
class UserRegistrationView(APIView):
permission_classes = ()
authentication_classes = ()
def post(self, request, *args, **kwargs):
# rest of your code here
私のソリューションは打撃を示しています。クラスを飾るだけです。
from Django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
@method_decorator(basic_auth_required(
target_test=lambda request: not request.user.is_authenticated
), name='dispatch')
class GenPedigreeView(View):
pass