7

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

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'
    ),
}
4

3 回答 3

11

你为什么会收到这个错误?

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

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

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

如果您将 AJAX 样式 API 与 一起使用SessionAuthentication,则需要确保为任何“不安全”的 HTTP 方法调用(例如 、 或请求)包含有效PUT的CSRF令牌PATCHPOSTDELETE

那你需要做什么?

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

于 2015-09-16T07:27:49.337 回答
6

愚蠢的我,我错过了TokenAuthenticationREST 设置中的框架:

设置.py

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

现在它按预期工作。

于 2015-09-16T07:20:56.617 回答
0

您需要在发送请求时传递 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 令牌,这是出于安全目的。

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

于 2020-10-22T05:08:08.907 回答