我使用Nginx和Gunicorn在VPS上部署Django 2.X博客。
当我通过Jquery AJAX将一些数据推送到Django后端时,出现了403 CSRF错误。我在Google上搜索了很多,但仍然不知道如何解决此问题。 我尝试使用相同的配置文件将它们部署到本地计算机上,一切正常。
首先,我没有在Django CSRF_USE_SESSIONS = True
中设置CSRF_COOKIE_HTTPONLY = True
和settings.py
。因此它们都是默认值False
。
我已经从Django document复制了AJAX示例代码:
// get csrftoken via JavaScript
function getCookie(name) {
let cookieValue = null
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';')
for (let i = 0; i < cookies.length; i++) {
let cookie = jQuery.trim(cookies[i])
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
break
}
}
}
return cookieValue
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method))
}
$.ajaxSetup({
beforeSend: (xhr, settings) => {
let $captchaMassage = $('#captcha-message')
let csrftoken = getCookie('csrftoken')
console.debug('csrftoken: ' + csrftoken)
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken)
}
if ($captchaMassage) {
$captchaMassage.text('please wait...')
}
}
})
这是我的AJAX:
$.ajax({
async: true,
method: 'POST',
url: '{% url "captcha_mine_taken_verification" %}',
dataType: 'json',
data: {'coinhive_captcha_token': token},
success: result => {
if (result.success) {
console.debug(result.data)
$captchaMassage.text('thanks to donate')
} else {
$captchaMassage.text('failure reason: ' + result.reason)
}
},
error: () => {
$captchaMassage.text('oh my god, something wrong...')
}
})
这是来自Chrome的请求标头:
POST /cloudsen_blog/captcha-mine/taken-verification HTTP/1.1
Host: 104.243.15.163
Connection: keep-alive
Content-Length: 55
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://104.243.15.163
X-CSRFToken: null <<<< this always null
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://104.243.15.163/cloudsen_blog/blog/article/5
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
这是我的Gunicorn配置文件:
import multiprocessing
# unix domain socket
# bind = 'unix:/home/cloudsen/work/deploy/webservers/sockets/nginx-gunicorn.sock'
# TCP
bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gevent'
errorlog = '/home/cloudsen/work/deploy/webservers/gunicorn/gunicorn.error.log'
accesslog = '/home/cloudsen/work/deploy/webservers/gunicorn/gunicorn.access.log'
proc_name = 'gunicorn_myblog'
这是我的Nginx配置文件:
worker_processes 2;
user cloudsen;
error_log /home/cloudsen/work/deploy/webservers/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
accept_mutex on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile off;
access_log /home/cloudsen/work/deploy/webservers/nginx/access.log combined;
# Arch Linux start
types_hash_max_size 4096;
server_names_hash_bucket_size 128;
# Arch Linux end
upstream app_server {
#server unix:/home/cloudsen/work/deploy/webservers/sockets/nginx-gunicorn.sock fail_timeout=0;
server 127.0.0.1:8000 fail_timeout=0;
}
server {
listen 80 default_server;
return 444;
}
server {
listen 80;
server_name 104.243.15.163;
client_max_body_size 4G;
keepalive_timeout 5;
location /favicon.ico {
access_log off;
log_not_found off;
}
location /static/ {
alias /home/cloudsen/work/python/project/RedQueen/collected_statics/;
}
location = / {
rewrite ^ /cloudsen_blog;
}
location / {
proxy_pass_header X-CSRFToken;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header Cookie $http_cookie;
proxy_redirect off;
proxy_pass http://app_server;
}
}
}
此外,当我在Chrome中调试时,我发现我的AJAX没有发送CSRF-TOKEN,并且document.cookie
始终为空字符串,因此getCookie('csrftoken')
始终返回Null。但是我不知道为什么。
感谢帮助~~~
答案 0 :(得分:0)
页面使用AJAX,没有任何HTML格式。 页面通过AJAX发出POST请求,并且该页面没有带有csrf_token的HTML表单,该表单会导致发送所需的CSRF cookie。
解决方案:在发送页面的视图上使用sure_csrf_cookie()。
通过使用ensure_csrf_cookie()
装饰器,终于解决了该问题。
from django.views.decorators.csrf import ensure_csrf_cookie
# use this on your view
@ensure_csrf_cookie
def go_article_detail_page(request: HttpRequest, article_pk: int):
pass
现在,每当您访问该页面时,Django都会在csrftoken
中发送一个document.cookie
。