web-dev-qa-db-ja.com

POST Django Frameworkを使用してRESTシンプルなJSONを作成する方法は? CSRFトークンが欠落しているか正しくない

JSONを使用してPOST Djangoフレームワークを使用して簡単なRESTリクエストを作成する方法を教えてくれる人を歓迎します。私はチュートリアルでこれの例をどこにも見ませんか?

これが、POSTするRoleモデルオブジェクトです。これは、データベースに追加したい新しいロールになりますが、500エラーが表示されます。

{
    "name": "Manager", 
    "description": "someone who manages"
}

Bashターミナルプロンプトでのcurlリクエストは次のとおりです。

curl -X POST -H "Content-Type: application/json" -d '[
{
    "name": "Manager", 
    "description": "someone who manages"
}]'


http://localhost:8000/lakesShoreProperties/role

URL

http://localhost:8000/lakesShoreProperties/roles

GET要求で動作し、データベース内のすべてのロールをプルダウンできますが、新しいロールを作成することはできません。権限が設定されていません。 views.pyで標準ビューを使用しています

class RoleDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Role.objects.all()
    serializer_class = RoleSerializer
    format = None

class RoleList(generics.ListCreateAPIView): 
        queryset = Role.objects.all()
        serializer_class = RoleSerializer
        format = None

このアプリのurls.pyでは、関連するURL-ビューマッピングが正しい:

url(r'^roles/$', views.RoleList.as_view()),
url(r'^role/(?P<pk>[0-9]+)/$', views.RoleDetail.as_view()),

エラーメッセージ:

{
    "detail": "CSRF Failed: CSRF token missing or incorrect."
}

ここで何が起こっており、これに対する修正は何ですか?ローカルホストはクロスサイトリクエストですか? @csrf_exemptRoleDetailRoleListに追加しましたが、何も変わらないようです。このデコレータをクラスに追加することもできますか、それともメソッドに追加する必要がありますか? @csrf_exemptデコレートを追加すると、私のエラーは次のようになります。

Request Method: POST
Request URL:    http://127.0.0.1:8000/lakeshoreProperties/roles/
Django Version: 1.5.1
Exception Type: AttributeError
Exception Value:    
'function' object has no attribute 'as_view'

次に、アプリ全体でCSRFを無効にし、次のメッセージを受け取りました。

{"non_field_errors":["Invalid data"]}私が知っているJSONオブジェクトが有効なjsonである場合。それはフィールド以外のエラーですが、私はここで立ち往生しています。

まあ、それは私のJSONが有効ではなかったことが判明しましたか?

{
    "name": "admin", 
    "description": "someone who administrates"
}

[
    {
        "name": "admin",
        "description": "someone who administrates"
    }
]

括弧[]で囲むと、POST要求が失敗します。しかし、jsonlint.comバリデータを使用すると、両方のjsonオブジェクトが検証されます。

Update:問題は、バックエンドではなく、PostManでPOSTを送信することでした。 https://stackoverflow.com/a/17508420/203312 を参照してください

44
user798719

おそらく、リクエストとともにCSRFトークンを送信する必要があります。チェックアウト https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#csrf-ajax

更新:既にCSRFを免除しようとしているので、これが役立つかもしれません(Django使用しているバージョンによって異なります): https://stackoverflow.com/a/14379073/977931

10
stellarchariot

CSRFは、Django REST Frameworkでデフォルトで免除されています。したがって、curl POST要求は正常に機能します。 POSTMANがcsrfトークンをCookiesで検出した場合、含まれているため、POSTMAN要求呼び出しはCSRFを誤って返しました。これは、Cookieをクリーンアップすることで解決できます。

34
Terry Lam

これは、REST Framework設定からのものです。settings.pyファイルでは、REST_FRAMEWORKには次のものが必要です。

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),
   'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.AllowAny',
    ),
}

これにより、csrf認証の代わりにトークン認証を使用するようにREST Frameworkが設定されます。許可をAllowAnyに設定することにより、目的の場所のみを認証できます。

24
pharingee

わかりました、もちろん今私は言ったことを取り戻します。 CSRFは意図したとおりに機能します。

POSTMANというPOSTプラグインを使用してchromeリクエストを作成していました。 CSRFが有効になっていると、私のPOST要求は失敗します。

しかし、カールPOSTリクエストを使用して

curl -X POST -H "Content-Type: application/json" -d '
{
    "name": "Manager",
    "description": "someone who manages"
}' http://127.0.0.1:8000/lakeshoreProperties/roles/

正常に動作します...中かっこを削除する必要がありました(つまり、[])。ロールの 's'の後にスラッシュがあることを確認しました。つまり、roles /、csrf enabledはエラーをスローしませんでした。

POSTMANを使用して呼び出すこととcurlを使用することの違いはわかりませんが、POSTMANはWebブラウザーで実行されるのが最大の違いです。つまり、クラスRoleList全体でcsrfを無効にしましたが、Curlでは同じ要求が1つ機能しますが、POSTMANでは失敗します。

10
user798719

現在のステータスに関する最新情報を提供し、いくつかの回答をまとめるには:

相互作用しているAPIと同じコンテキスト内で行われるAJAX要求は、通常SessionAuthenticationを使用します。これにより、ユーザーがログインすると、AJAXリクエストはすべて、Webサイトの他の部分で使用されるのと同じセッションベースの認証を使用して認証されます。

通信しているAPIとは異なるサイトで作成されたAJAXリクエストは、通常、TokenAuthenticationなどの非セッションベースの認証スキームを使用する必要があります。

したがって、SessionAuthenticationTokenAuthenticationに置き換えることを推奨する回答で問題を解決できますが、必ずしも完全に正しいとは限りません。

これらのタイプの攻撃から保護するには、2つのことを行う必要があります。

  1. GETHEADOPTIONSなどの「安全な」HTTP操作を使用して、サーバー側の状態を変更できないようにしてください。

  2. POSTPUTPATCHDELETEなどの「安全でない」HTTP操作には、常に有効なCSRFトークンが必要であることを確認してください。 SessionAuthenticationを使用している場合、すべてのPOSTPUTPATCH、またはDELETE操作に有効なCSRFトークンを含める必要があります。 。

AJAXリクエストを行うには、=で説明されているように、HTTPヘッダーにCSRFトークンを含める必要があります。 Django documentation。

したがって、たとえば this answer が示唆するように、csrfがヘッダーに含まれていることが重要です。

参照: AJAX、CSRFおよびCORSの操作、Django RESTフレームワークドキュメント

4
Wtower

あなたが言ったようにあなたのURLは

http://localhost:8000/lakesShoreProperties/roles

Postmanにはlocalhostに関する問題があります。代わりにPOSTを127.0.0.1:8000/your-api/endpointに送信すると、私にとってはうまくいきませんでした。

3
Thosse

古い Postman はcsrfトークンに問題があります。これは、Cookieで機能しないためです。

postman の新しいバージョンに切り替えることをお勧めします。これはcookieで機能し、この問題に再び直面することはありません。

1

AllowAnyパーミッションを設定していて、csrfの問題に直面している場合

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny'
    ]
}

次に、settings.pyは問題を解決します

REST_SESSION_LOGIN = False
0
navyad