Django 服务器 403(CSRF 令牌丢失或不正确)

Django server 403 (CSRF token missing or incorrect)

我有一个带有 python 命令行客户端的基本 Django 服务器,用于 posting 到此服务。我有一个登录功能和一个 post 功能。即使 CSRF 的 cookie 是从登录功能设置的,当我在登录后尝试访问 post_product 端点时,服务器仍然说禁止。

我已经为此排查了好几天,但一直没有成功。

/api/login/函数:

from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse

@csrf_exempt
def handle_login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(request, username=username, password=password)

        if user is not None:
            if user.is_active:
                login(request, user)
                if user.is_authenticated:
                    return HttpResponse(author.name + ' is logged in, Welcome!', status=201, content_type='text/plain')
                return HttpResponse(data)

            else:
                return HttpResponse('disabled account', status=400, content_type='text/plain')

        else:
            return HttpResponse('invalid login', status=400, content_type='text/plain')

    else:
        return HttpResponse('request method invalid ' + request.method, status=400, content_type='text/plain')


/api/postproduct/函数:

def post_story(request):
    if request.method == 'POST' and request.user.is_authenticated:
        # Pull product details from request.
        # Validate product details.
        # Create model and save.

Python终端客户端

FAILURE_MESSAGE = "The server responded with an unsuccessful code: "


def run():
    url ='http://127.0.0.1:8000' # For debugging
    logged_in = false
    with requests.session() as session:
        while True:
            command = input("""Enter one of the following commands:
            login 
            post \n""")

            # login case.
            if command == "login":
                url = user_inputs[1]
                logged_in = login(session, url)
                continue

            # post case.
            elif command == "post" and logged_in:

                post(session, url)                    
                continue

            else:
                print('incorrect command')
                continue


def login(session, url):
    username = input("Enter your username: \n")
    password = input("Enter your password: \n")
    response = session.post(url + "/api/login/", data={'username': username, 'password': password})

    # If any response but success notify user.
    if response.status_code != 201:
        print(FAILURE_MESSAGE + str(response.status_code))
        return False
    else:
        print("Successfully logged in!")
        return True


def post(session, url):
    # Check session is authenticated
    if 'csrftoken' not in session.cookies:
        print("Not authenticated, have you logged in to a service?")
        return

    # Omitted : prompt user for productname, category, price and details.

data = {'productname': productname, 'category': category, 'price': price, 'details': details}
    data_json = json.dumps(data)
    payload = {'json_payload': data_json}
    if not session_is_active():
        print("You aren't logged into any services")
        return
    else:
        response = session.post(url + "/api/postproduct/", data=payload)
        print(6)
        if response.status_code != 201:
            print(FAILURE_MESSAGE + str(response.status_code))
            return
        print("Post was successful")

当我 运行 客户端时,登录工作正常并且在检查时确实设置了 csrf cookie。但是,当我尝试 post 时,服务器以 403 禁止响应。从服务器的输出:

[15/Aug/2019 15:45:23] "POST /api/login/ HTTP/1.1" 201 42
Forbidden (CSRF token missing or incorrect.): /api/postproduct/

Django 的 CSRF 保护要求您 post CSRF cookie 和隐藏在表单字段中的令牌。 For AJAX requests,可以设置一个header代替表单域。

尝试如下操作(未经测试):

headers = {'X-CSRFToken': session.cookies['csrftoken']}
response = session.post(url + "/api/postproduct/", data=payload, headers=headers)

向 Django 后端提交请求时出现错误 = csrf 禁止(CSRF 令牌丢失或不正确。):

在表单中,包含 {% csrf_token %},它会生成一个带有 csrf 令牌值的输入标签, 在请求中,让 headers 包含‘X-CSRFTOKEN

headers: {
                content_type: 'application/json',
                'X-CSRFToken': "{{ csrf_token }}"
            },