AngularJS не отправляет-X_XSRF-TOKEN

Я разрабатываю мобильное приложение Ionic, чтобы поговорить с моим сервером Rails с использованием API JSON. Я прочитал, что AngularJS автоматически обрабатывает защиту XSRF, отправив заголовок X-XSRF-TOKEN в запрос POST если первый GET возвращает файл cookie с именем XSRF-TOKEN

Я обновил Rails application_controller.rb следующим образом:

class ApplicationController < ActionController::Base
  protect_from_forgery
  after_filter :set_access_control_headers
  after_filter :set_csrf_cookie_for_ng

  def after_sign_in_path_for(resource)
    main_path
  end

  def after_sign_out_path_for(resource)
    login_path
  end

  ##
   # Sets headers to support AJAX Cross-Origin Resource Sharing.
   # This is only needed for testing within browser (i.e. mobile apps do not need it).
   ##
  def set_access_control_headers
    # hosts who can make AJAX requests
    headers['Access-Control-Allow-Origin'] = 'http://localhost:8100'
    headers['Access-Control-Request-Method'] = '*'
    headers['Access-Control-Allow-Headers'] = 'accept, content-type, x-xsrf-token'
    # allow clients to use cookies to track session state
    headers['Access-Control-Allow-Credentials'] = 'true'
  end

  ##
   # Sets a cookie containing an XSRF token. This should be returned by the
   # client as a header field named 'X-XSRF-TOKEN'
  def set_csrf_cookie_for_ng
    cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
  end

protected

  def verified_request?
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  end
end

Код AngularJS:

$http({
  method: 'POST',
  url: $scope.getBackendUrl() + '/reports.json',
  params: params,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})

Я взял дампы Wireshark и вижу, что сервер Rails отправляет через Cookie (и я могу прочитать это в AngularJS). Тем не менее, AngularJS не отправляет заголовок X-XSRF-TOKEN на мой сервер Rails-сервера, вызывая WARNING: Can't verify CSRF token authenticity.

Я прочитал кучу вопросов SO безрезультатно. Например, заголовки XSRF не устанавливаются в AngularJS

Я добавил материал заголовка CORS, чтобы я мог протестировать его в Chrome. Опять же, я вижу, что cookie проходит с сервера, но заголовок не отправляется обратно. Однако cookie отправляется обратно в поле заголовка "Cookie".

Может ли кто-нибудь увидеть то, что у меня пропало, или что я могу попытаться решить? В настоящее время я разбираю поле заголовка Cookie в запросе, чтобы вытащить токен и проверить подлинность, чтобы обойти проблему во время тестирования.

def verified_request?
  # should just need to do the below, but for some reason AngularJS is not setting 'X-XSRF-TOKEN'
  #super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  if(super)
    true
  else
    cookie = request.headers['Cookie'] || ""
    value = cookie.nil? ? "" : CGI.unescape( cookie.gsub(/.*XSRF-TOKEN=(.+);.*/, '\1') )
    form_authenticity_token == value
  end
end

Версии:

  • Рельсы 3.2.3
  • Ионный 1.1.6 (который связывает в AngularJS)

Ответ 1

Согласно документации

$ http: заголовок не будет установлен для междоменных запросов.

Если вам нужно использовать CORS, вы также будете выполнять запросы на междоменные запросы. По-прежнему сможет сделать это самостоятельно с помощью $ httpInterceptor. Сначала вы читаете значение cookie, а затем присоединяете заголовок к конфигу до того, как запрос будет запущен.

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
    }
    return null;
}
module.factory('XSRFInterceptor', function() {
    var XSRFInterceptor = {
        request: function(config) {
            var token = readCookie('XSRF-TOKEN');
            if (token) {
                config.headers['X-XSRF-TOKEN'] = token;
            }
            return config;
        }
    };
    return XSRFInterceptor;
}]);
module.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('XSRFInterceptor');
}]);

Ответ 2

Просто для тех, кто пришел сюда, как я, пытаясь понять, почему Angular не отправляет заголовок X-XSRF-TOKEN:

В моем случае я не обращал внимания, что я отправляю файл cookie XSRF-TOKEN с флагом HttpOnly.

Ответ 3

Настройка httpProvider с помощью

$ httpProvider.defaults.xsrfCookieName = 'csrftoken'; $ httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; не устанавливает заголовок X-CSRFToken для междоменных запросов, в то время как запросы к исходным доменам являются точными.

Заголовки Access-Control-Allow -... настроены так, чтобы позволить CORS с кукисами и заголовком X-CSRFToken:

Access-Control-Allow-Headers: x-request-with, content-type, accept, origin, authorization, x-csrftoken Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS Access-Control- Разрешить-Происхождение: origin_url Access-Control-Allow-Credentials: true