记一次解决Django 403

想直接看解决方案,可翻页到最後面

提交无法登陆,打开F12调试工具查看ajax返回信息:403 CSRF cookie not set.
记一次解决Django 403_第1张图片

网上给出的大体是3种解决方案

  • 禁用django的crfs中间件
    这个方法一劳永逸,但是不太安全,而且我在本地(ubuntu+Python 2.7.12+django1.11.2)上面测试可用,但是在服务器上(Centos6.5+Python 2.6.6+Django1.6)上面禁用不生效,不知道是不是我姿势不对,而且感觉全局禁用不太安全。
    settings.py
MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
  • 在template文件的表单中加入{% csrf_token %}
    这个方法应该是最安全的,但是因为我是一开始就设计的前后端页面,用ajax调用页面,如果现在重新写有点麻烦
  • 创建一个忽略指定路由的csrf检测
    在settings.py目录下创建一个functions.py的文件
import re
class IgnorecsrfMiddleware(object):
    def process_request(self, request, **karg):
        if re.match(r'^/api/login$', request.path):
            request.csrf_processing_done = True
            return None

然后在settings.py中加入这个中间件

MIDDLEWARE = [
    'mysites.functions.IgnorecsrfMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

但是我测试发现报错:TypeError: object() takes no parameters。
解决思路:
类IgnorecsrfMiddleware的父类是object,它提示 object() takes no parameters。意思是object__init__ 没有参数,总的来说不能直接使用object,那么我们可以重写__init__,但是这样比较麻烦,而且可能出现其他错误,那我们来看看其他中间件是怎么定义的

from django.utils.deprecation import MiddlewareMixin
class CsrfViewMiddleware(MiddlewareMixin):
    # more code...

class XFrameOptionsMiddleware(MiddlewareMixin):
    # more code...

我们可以看到,大都是使用Django的MiddlewareMixin作为父类,那么我们也尝试一下直接将MiddlewareMixin作为我自定义中间件的父类,结果当然是成功了啊。
下面贴上代码:
settings.py

#more code
MIDDLEWARE = [
    'OpsMS.functions.IgnorecsrfMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
#more code

functions.py

import re
from django.utils.deprecation import MiddlewareMixin
class IgnorecsrfMiddleware(MiddlewareMixin):
    def process_request(self, request, **karg):
        if re.match(r'^/api/login$', request.path):
            request.csrf_processing_done = True
            return None

如果你有多个url需要绕过检测,可以在定义一个列表,然后用for循环遍历,或者通过正则来匹配(如:需要绕过csrf的,统一用 /api/IgnoreCsrf/xxxx 这种格式)

另一个比较有效的方法

更新:
其实上面的方法都不能解决我的CRSF的问题,后来发现了一个临时解决crsf问题的方法:
在每个有post的地方加入一个装饰器就可以解决了:
@csrf_exempt

你可能感兴趣的:(python)