记一次解决Django 403

来源:互联网 发布:活动致辞知乎 编辑:程序博客网 时间:2024/06/14 14:48

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

提交无法登陆,打开F12调试工具查看ajax返回信息:403 CSRF cookie not set.
这里写图片描述

网上给出的大体是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 reclass 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 MiddlewareMixinclass CsrfViewMiddleware(MiddlewareMixin):    # more code...class XFrameOptionsMiddleware(MiddlewareMixin):    # more code...

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

#more codeMIDDLEWARE = [    '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 refrom django.utils.deprecation import MiddlewareMixinclass 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

阅读全文
0 0
原创粉丝点击