我正在开发一个Ionic
移动应用程序,Rails
使用JSON API 与我的后端服务器通信.我已经读过,如果第一个请求返回一个名为的cookie ,AngularJS将通过X-XSRF-TOKEN
在POST
请求上发送标头来自动处理XSRF保护GET
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问题无济于事.例如, 未在AngularJS中设置XSRF标头
我添加了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中捆绑)
Jeremy Wilke.. 13
根据文件
$ 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'); }]);
Eugene.. 9
对于像我一样来到这里的人试图找出为什么Angular没有发送X-XSRF-TOKEN标头:
在我的情况下,我没有注意到我正在发送带有HttpOnly标志的XSRF-TOKEN cookie .
根据文件
$ 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'); }]);
对于像我一样来到这里的人试图找出为什么Angular没有发送X-XSRF-TOKEN标头:
在我的情况下,我没有注意到我正在发送带有HttpOnly标志的XSRF-TOKEN cookie .