【问题标题】:AngularJS is not sending-X_XSRF-TOKENAngularJS 没有发送-X_XSRF-TOKEN
【发布时间】:2014-09-30 03:23:01
【问题描述】:

我正在开发一个 Ionic 移动应用程序,以使用 JSON API 与我的后端 Rails 服务器通信。如果第一个GET 请求返回一个名为XSRF-TOKEN 的cookie,我已经通过在POST 请求上发送标头X-XSRF-TOKEN 来阅读AngularJS will automatically handle XSRF protection

我已将我的 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 headers not being set in 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

版本:

  • Rails 3.2.3
  • Ionic 1.1.6(在 AngularJS 中捆绑)

【问题讨论】:

    标签: ruby-on-rails angularjs cors ionic-framework


    【解决方案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');
    }]);
    

    【讨论】:

    • 谢谢!我错过了$http doco 中的那一行。这对于为什么我没有看到来自 Angular 的标题是有道理的。非常感谢。
    【解决方案2】:

    只适合像我一样来到这里试图弄清楚为什么 Angular 不发送 X-XSRF-TOKEN 标头的人:

    在我的情况下,我没有注意到我正在发送带有 HttpOnly 标志的 XSRF-TOKEN cookie。

    【讨论】:

    • 这对我来说远非显而易见,但 它确实让我工作。谢谢@eugene!
    • 为什么这不是一个好主意?这不会在浏览器中打开对 cookie 的访问。 Angular 的$http 服务以安全为代价为我们提供的“便利”真的值得吗?还是我读错了?
    【解决方案3】:

    使用 httpProvider 配置

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

    跨域请求不设置X-CSRFToken头,对原域的请求正常。

    Access-Control-Allow-... 标头设置为允许带有 cookie 和 X-CSRFToken 标头的 CORS:

    Access-Control-Allow-Headers:x-requested-with、content-type、accept、origin、authorization、x-csrftoken 访问控制允许方法:GET、POST、PUT、PATCH、DELETE、OPTIONS 访问控制允许来源:origin_url 访问控制允许凭据:true

    【讨论】:

      猜你喜欢
      • 2014-09-08
      • 2019-01-05
      • 2018-06-13
      • 2013-07-31
      • 2014-04-13
      • 2016-07-14
      • 1970-01-01
      • 2018-02-23
      • 2017-01-06
      相关资源
      最近更新 更多