• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

django使用ajax PUT/DELETE方法请求报错解决“forbidden (CSRF token missing or incorrect.)

武飞扬头像
天下·第二
帮助1

Django IIS使用ajax PUT/DELETE方法请求报错解决

1.报错内容:

后端报错内容

[2022-11-15 10:11:48,961] [log.py:log_response->228]-[WARNING]-Forbidden: /teams/data_structure_detail/45/
[2022-11-15 10:11:48,961] [basehttp.py:log_message->157]-[WARNING]-"PUT /teams/data_structure_detail/45/ HTTP/1.1" 403 58

前端返回报错
学新通
2.报错原因
django,会对合法的跨域访问做这样的检验,cookies里面存储的’csrftoken’,和post的header里面的字段”X-CSRFToken’作比较,只有两者匹配,才能通过跨域检验。否则会返回这个错误:CSRF Failed: CSRF token missing or incorrect,而我们django的后端认证csrf方式是自带的用户验证机制。即使注释了CSRF中间件也还是一样无法通过
学新通

点开django CSRF中间件的源码我们可以看到返回报错的源码

class CsrfViewMiddleware(MiddlewareMixin):
    """
    Require a present and correct csrfmiddlewaretoken for POST requests that
    have a CSRF cookie, and set an outgoing CSRF cookie.

    This middleware should be used in conjunction with the {% csrf_token %}
    template tag.
    """
    # The _accept and _reject methods currently only exist for the sake of the
    # requires_csrf_token decorator.
    def _accept(self, request):
        # Avoid checking the request twice by adding a custom attribute to
        # request.  This will be relevant when both decorator and middleware
        # are used.
        request.csrf_processing_done = True
        return None
	
	############################### CSRF检测报错  #######################################
    def _reject(self, request, reason):
        response = _get_failure_view()(request, reason=reason)
        log_response(
            'Forbidden (%s): %s', reason, request.path,
            response=response,
            request=request,
            logger=logger,
        )
        return response
	。。。
	。。。
	。。。
	
    def process_view(self, request, callback, callback_args, callback_kwargs):
        if getattr(request, 'csrf_processing_done', False):
            return None

        # Wait until request.META["CSRF_COOKIE"] has been manipulated before
        # bailing out, so that get_token still works
        if getattr(callback, 'csrf_exempt', False):
            return None
		
		#################### 前端ajax传来的方法里没有找到,因此无法进去进入_accept函数 给request.csrf_processing_done = True 赋值   #############################
        # Assume that anything not defined as 'safe' by RFC7231 needs protection
        if request.method not in ('GET', 'HEAD', 'OPTIONS', 'TRACE'):
            if getattr(request, '_dont_enforce_csrf_checks', False):
                # Mechanism to turn off CSRF checks for test suite.
                # It comes after the creation of CSRF cookies, so that
                # everything else continues to work exactly the same
                # (e.g. cookies are sent, etc.), but before any
                # branches that call reject().
                return self._accept(request)
学新通

我们再来看看_accept函数的翻译

    # The _accept and _reject methods currently only exist for the sake of the
    # requires_csrf_token decorator.
    def _accept(self, request):
        # Avoid checking the request twice by adding a custom attribute to
        # request.  This will be relevant when both decorator and middleware
        # are used.
        """
        翻译
        #通过添加自定义属性来避免检查请求两次
		#请求。这将与装饰器和中间件都相关
		#使用。
		"""
        request.csrf_processing_done = True
        return None
class ClientHandler(BaseHandler):
    """
    A HTTP Handler that can be used for testing purposes. Use the WSGI
    interface to compose requests, but return the raw HttpResponse object with
    the originating WSGIRequest attached to its ``wsgi_request`` attribute.
    """
    def __init__(self, enforce_csrf_checks=True, *args, **kwargs):
        self.enforce_csrf_checks = enforce_csrf_checks
        super().__init__(*args, **kwargs)

    def __call__(self, environ):
        # Set up middleware if needed. We couldn't do this earlier, because
        # settings weren't available.
        if self._middleware_chain is None:
            self.load_middleware()

        request_started.disconnect(close_old_connections)
        request_started.send(sender=self.__class__, environ=environ)
        request_started.connect(close_old_connections)
        request = WSGIRequest(environ)
        # sneaky little hack so that we can easily get round
        # CsrfViewMiddleware.  This makes life easier, and is probably
        # required for backwards compatibility with external tests against
        # admin views.
		"""
		译文
		#鬼鬼祟祟的小黑客,这样我们就可以轻松绕过
		# CsrfViewMiddleware。这使生活更容易,而且可能是
		#需要与外部测试向后兼容
		# admin视图。
        request._dont_enforce_csrf_checks = not self.enforce_csrf_checks
学新通

通过以上问题的分析,我们可以通过以下的解决方法来解决ajax PUT/DELETE方法跨域检测不通过的文通

3.解决方法

定义一个中间件,然后在setting.py文件中注册即可
自定义中间件CsrfExemptMiddleware.py

from django.utils.deprecation import MiddlewareMixin


class CsrfExemptMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.csrf_processing_done = True
        request._dont_enforce_csrf_checks = True

setting.py中注册中间件

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'system_register.middleware.CsrfExemptMiddleware',
	...
]

注:另外如果是IIS部署项目的化有可能会遇到项目无法使用PUT/DELETE方法的问题,此时我们需要在web.config文件中增加以下代码

<modules runAllManagedModulesForAllRequests="true">
   <remove name="WebDAVModule"/>
</modules>
<handlers>
<remove name="WebDAV" />
</handlers>

下面是完整的配置代码

<?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
			<modules>
			  <remove name="WebDAVModule" />
			</modules>
			<handlers>
			<remove name="WebDAV" />
				<add name="Python FastCGI" path="*" verb="*" modules="FastCgiModule" scriptProcessor="D:\Program Files (x86)\Python\Python37\python.exe|E:\xxxxxxxxx\xxxxxxxxx\wfastcgi.py" resourceType="Unspecified" requireAccess="Script" />
			</handlers>
			<httpRedirect enabled="false" destination="" exactDestination="false" childOnly="false" httpResponseStatus="Permanent" />
			<security>
				<requestFiltering>
					<requestLimits maxAllowedContentLength="419430400" />
				</requestFiltering>
			</security>
        <httpErrors errorMode="Detailed" />
        <asp scriptErrorSentToBrowser="true" />
        </system.webServer>
        <appSettings>
            <add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()" />
            <add key="PYTHONPATH" value="E:\xxxxxxxxx\xxxxxxxxx" />
            <add key="DJANGO_SETTINGS_MODULE" value="system_register.settings" />
        </appSettings>
		<system.web>
        <httpRuntime executionTimeout="6000" maxRequestLength="419430400" />
        <customErrors mode="Off" />
        <compilation debug="true" />
    </system.web>
    </configuration>
学新通

重启项目重新访问接口即可。

以上的内容希望对你有帮助!

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanheeahae
系列文章
更多 icon
同类精品
更多 icon
继续加载