【问题标题】:Django + DRF: 403 FORBIDDEN: CSRF token missing or incorrectDjango + DRF:403 FORBIDDEN:CSRF 令牌丢失或不正确
【发布时间】:2015-12-12 15:39:06
【问题描述】:

我有一个尝试使用 Django + DRF 后端进行身份验证的 Android 客户端应用程序。但是,当我尝试登录时,我得到以下响应:

403: CSRF Failed: CSRF token missing or incorrect.

请求被发送到http://localhost/rest-auth/google/,正文如下:

access_token: <the OAuth token from Google>

是什么原因造成的?客户端没有 CSRF 令牌,因为 POST 进行身份验证是客户端和服务器之间发生的第一件事。我检查了很多过去的问题,同样的问题,但我找不到任何解决方案。

Django端的相关设置是这样的:

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.ModelBackend",
    "allauth.account.auth_backends.AuthenticationBackend"
)

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.core.context_processors.request",
    "django.contrib.auth.context_processors.auth",
    "allauth.account.context_processors.account",
    "allauth.socialaccount.context_processors.socialaccount"
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.facebook',
    'allauth.socialaccount.providers.google',

    'django.contrib.admin',

    # REST framework
    'rest_framework',
    'rest_framework.authtoken',
    'rest_auth',
    'rest_auth.registration',
)

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ( 
        'rest_framework.permissions.IsAuthenticated'
    ),
}

【问题讨论】:

    标签: django django-rest-framework csrf django-allauth django-rest-auth


    【解决方案1】:

    您需要在发送请求时传递 csrf 令牌让我们查看给定的代码:

    function getCookie(name) {
     var cookieValue = null;
     if (document.cookie && document.cookie !== '') {
         var cookies = document.cookie.split(';');
         for (var i = 0; i < cookies.length; i++) {
             var cookie = cookies[i].trim();
             // 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;
    }
    
    const check = () => {
    
     const endPoint = '/api/check/'
     const csrftoken = getCookie('csrftoken'); // getting the cookie to pass as csrf token
    
     return fetch(baseUrl + endPoint,{
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': csrftoken
            },
            
        })
        .then(response => {
            if (response.ok) {
                return response
            }
            else { 
                if (response.status === 401 && response.statusText === 'Unauthorized'){ // if it is un authorized then dispatch the logout
                    dispatch(logout());
                }
                var error = new Error('Error: '+ response.status + ': ' + response.statusText); 
                error.response = response;  
                throw error; 
            }
    
        },               
        error => {
            var errmess = new Error(error.message); 
            throw errmess;
        })
        .then( data => data.json())
        .then(data => console.log(data))
        .catch(error => console.log(error.message)); 
       }
    

    请记住一件事,无论您是发送 GET PUT 还是 POST 请求,都需要发送 csrf 令牌,这是出于安全目的。

    希望我的回答对你有所帮助。

    【讨论】:

      【解决方案2】:

      真傻,我错过了 REST 设置中的 TokenAuthentication 框架:

      settings.py

      REST_FRAMEWORK = {
          'DEFAULT_AUTHENTICATION_CLASSES': (
              'rest_framework.authentication.TokenAuthentication',
          )
      }
      

      现在它可以正常工作了。

      【讨论】:

        【解决方案3】:

        为什么会出现此错误?

        由于您尚未在设置中定义AUTHENTICATION_CLASSES,DRF 使用以下默认身份验证类。

        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.BasicAuthentication'
        )
        

        现在,SessionAuthentication 强制使用 CSRF Token。如果您没有传递有效的 CSRF 令牌,则会引发 403 错误。

        如果您使用带有 SessionAuthentication 的 AJAX 样式 API,您将 需要确保为任何“不安全”HTTP 包含有效的 CSRF 令牌 方法调用,如PUTPATCHPOSTDELETE请求。

        那你需要做什么?

        由于您使用的是 TokenAuthentication,因此您需要在 DRF 设置中的 AUTHENTICATION_CLASSES 中明确定义它。这应该可以解决您的 CSRF 令牌问题。

        【讨论】:

        • 你说我们必须传递一个有效的 CSRF 令牌。我在哪里可以找到这个令牌?就我而言,当我尝试使用 rest-auth/login/ 端点登录时,问题就出现了。但这是客户端和服务器的第一次接触,所以客户端不知道令牌。
        • 查看这个 Django 文档link 以获取用于 Ajax 请求的 CSRF 令牌。
        • 谢谢@rahul-gupta,但我不在网络环境中。我在 c# 环境(Xamarin)上。但无论如何,在一个rest客户端应用程序中,如果服务器没有告诉他,客户端就无法知道csrf。
        • 那么您应该使用不同的身份验证类,因为SessionAuthentication 需要发送 CSRF 令牌。您需要在您的设置或特定视图中明确定义该特定身份验证类。
        猜你喜欢
        • 2013-08-15
        • 2013-12-03
        • 2015-10-15
        • 2017-09-10
        • 1970-01-01
        • 2019-12-22
        • 1970-01-01
        • 2021-11-13
        • 2012-04-20
        相关资源
        最近更新 更多