【问题标题】:Django refuses request from Python requestsDjango 拒绝来自 Python 请求的请求
【发布时间】:2020-04-15 15:02:43
【问题描述】:

我有一个 Django 视图,当用户执行某个任务时,外部 Python 微服务会检索一些数据,然后将一些数据发送到 Django 视图,该视图应该在模板上将其显示给用户。要发送我使用 Python 请求的数据,问题是 Django 拒绝了 Json 响应,原因有两个:1)未设置 CSRF 令牌 2)视图为 @login_required

这是我的看法:

@login_required
def myTestView(request):    

    if request.method == 'POST':
        received_json_data=json.loads(request.body)
        print(received_json_data)
        print('received.')

这是我发送响应的方式:

import requests

req = requests.post('http://127.0.0.1:8000/myTestView/', json={"test": "json-test"})
print('SENT')

使用实际代码,我从 Django 收到此错误:

Forbidden (CSRF cookie not set.): /myTestView/
[2019-12-24 15:36:08,574] log: WARNING - Forbidden (CSRF cookie not set.): /myTestView/

我知道我可以使用@csrf_exempt,但由于我发送的数据是个人数据,我希望它尽可能安全,所以我需要找到一种方法来发送 CSRF 令牌。我需要做的第二件事是如何使用请求“登录”?

【问题讨论】:

标签: python django python-requests


【解决方案1】:

我喜欢这个问题,所以我将尝试详细描述整个过程。

  1. 服务器端

第一步是获取 csrf_token,您将在后续发布请求中使用它。

之后,您必须对会话进行身份验证。

所以让我们编写一个视图来服务 get 以获取 csrf_token 并发布以验证会话。受保护视图的想法相同。

我们通过身份验证后,就可以访问受保护的视图了。

import json

from django.contrib.auth import authenticate, login
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseForbidden
from django.middleware.csrf import get_token


@login_required
def myTestView(request):
    if request.method == 'POST':
        data = request.POST.get('data')
        print(json.loads(data))
        print('received.')

    response = HttpResponse(get_token(request))
    return response


def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)

        if user is not None:
            login(request, user)
            return HttpResponse('authenticated')
        else:
            return HttpResponseForbidden('wrong username or password')

    response = HttpResponse(get_token(request))
    return response

  1. 客户端

requests.post 不适合此任务,因为它无法跟踪(或者很难)请求 cookie 和标头。

但您可以为此目的使用 requests.session()

Django 无法处理 json 中的 csrf_token,这就是为什么你必须在请求数据中传递 json。

import json

import requests


session = requests.session()
token = session.get('http://127.0.0.1:8000/login/')

session.post('http://127.0.0.1:8000/login/',
             data={
                 'username': '<username>',
                 'password': '<password>',
                 'csrfmiddlewaretoken': token})

token = session.get('http://127.0.0.1:8000/myTestView/')
data = json.dumps({'test': 'value'})
session.post('http://127.0.0.1:8000/myTestView/',
             data={
                 'csrfmiddlewaretoken': token,
                 'data': data})

介意为视图添加 urls.py

我检查了这段代码,它运行良好。如果有人知道如何改进它,我会很乐意更新它。

【讨论】:

  • 嘿!感谢您的回答!我现在正在测试它。我想了解的一件事:所以您添加的登录视图将仅用于验证来自我提到的外部脚本的请求?我问是因为要处理网站上的身份验证,我使用的是 Django-Allauth 提供的完全不同的视图
  • 另一件事,在'session.post'之后,/view/是什么意思?
  • 好的,我想我已经掌握了窍门!我可以让用户登录,但我仍然收到“CSRF 令牌丢失或不正确”!
  • 我更正了答案,view/被myTestView/错误替换了
  • 登录视图怎么样。我添加它是因为您没有提供实际验证用户的方式。我认为您可以使用 Django-Allauth 身份验证视图来做同样的事情。
猜你喜欢
  • 1970-01-01
  • 2021-01-04
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-17
  • 2012-12-14
  • 2019-12-06
相关资源
最近更新 更多