简体   繁体   中英

Django authentication : CSRF Failed

Sometimes I can't login to my application.

The authentication is handled by Django API.

But sometimes it returns a 403 error with this value in the result object :

responseText: "{"detail":"CSRF Failed: CSRF token missing or incorrect."}"

And yet in my application, I have :

angular.module('app')
  .config(function(ezLayoutProvider, $httpProvider) {
    ezLayoutProvider.register(layoutName, {templateUrl: './main.html'});
    ezLayoutProvider.setDefault(layoutName);
    var getCookie = function(cookieName) {
      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();
      if (cookie.substring(0, cookieName.length + 1) === (cookieName + '=')) {
        cookieValue = decodeURIComponent(cookie.substring(cookieName.length + 1));
        break;
      }
    }
  }
  return cookieValue;
};

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
$httpProvider.defaults.headers.common['X-CSRFToken'] = getCookie('csrftoken');
console.log($httpProvider.defaults.headers.common);
})

And the consoles shows the token is properly set before I try to login.

A weird thing is that, once I clear my cookies and cache from the browser, it works.

So I'm guessing it has to do with Django's session somehow ?

Here is a piece of my settings.py :

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.DjangoModelPermissions',
    ),
}

REST_PROXY = {
    'HOST': 'http://localhost:5000'
}

CORS_ORIGIN_ALLOW_ALL = True

AUTHENTICATION_BACKENDS = (
    'auth.ldap.LDAPBackendFR',
    'auth.ldap.LDAPBackendUS',
    'auth.ldap.LDAPBackendHK',
    'auth.ldap.LDAPBackendIN',
    'django.contrib.auth.backends.ModelBackend',
)

Another weird point, is that it seems to work also with :

Object {Accept: "application/json, text/plain, */*", X-Requested-With: "XMLHttpRequest", X-CSRFToken: null}

as $httpProvider.defaults.headers.common .

Why are you using $httpProvider.defaults.headers.common['X-CSRFToken'] = getCookie('csrftoken'); ? I'm not an AngularJS expert, but that line shouldn't be needed.

This is what the Django documentation says:

If you're using AngularJS 1.1.3 and newer, it's sufficient to configure the $http provider with the cookie and header names:

 $http.defaults.xsrfCookieName = 'csrftoken'; $http.defaults.xsrfHeaderName = 'X-CSRFToken'; 

From my understanding, this is how your code should look like:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/* Not needed, causes harm! */
/* $httpProvider.defaults.headers.common['X-CSRFToken'] = getCookie('csrftoken'); */
console.log($httpProvider.defaults.headers.common);

This should also explain why with X-CSRFToken: null is working.

If I'm not mistaken Django's CSRF have a timeframe where they are working.

From time to time I do have this issue and refreshing the form and therefore the CSRF does work for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM