web-dev-qa-db-ja.com

Django Rest Framework remove csrf

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を無効にするにはどうすればよいですか?

84
Irene Texas

このエラーが発生する理由

これは、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エラーが処理されるはずです。

180
Rahul Gupta

より簡単なソリューション:

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})
12
bixente57

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')

ジョブが完了します!

10
Syed Faizan

セッションベースの認証を使用したくない場合は、REST_AUTHENTICATION_CLASSESからSession Authenticationを削除できます。これにより、すべてのcsrfベースの問題が自動的に削除されます。ただし、その場合、Browseable APIは機能しない可能性があります。

さらに、このエラーはセッション認証でも発生しないはずです。 APIにはTokenAuthenticationなどのカスタム認証を使用し、認証トークンとともにリクエストでAccept:application/jsonおよびContent-Type:application/json(jsonを使用している場合)を送信するようにしてください。

8
hspandher

役に立つ答えを見つけられなかったすべての人に。はい。たとえば、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()),
8
user3479125

私は同じ問題に見舞われています。私はこれに従いました 参照 そしてそれは働きました。解決策はミドルウェアを作成することです

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,
)
3
Venkatesh Mondi

アプリケーションに排他的な仮想環境を使用している場合、他のアプリケーションを効果的に使用せずに次のアプローチを使用できます。

rest_framework/authentication.pyauthenticateクラスの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

1
Reetesh Ranjan

上記の回答のいくつかを試してみましたが、別のクラスを作成することは少し面倒だと感じました。

参考までに、ユーザー登録のために関数ベースのビューメソッドをクラスベースのビューメソッドに更新しようとしたときに、この問題に遭遇しました。

クラスベースビュー(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
1
Mike Hawes

私のソリューションは打撃を示しています。クラスを飾るだけです。

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
1
Jak Liao