我正在为Drupal 7网站构建一个新的AngularJS前端。这是使用服务模块进行基于会话的身份验证,使用CORS跨两个域。我能够使用Drupal进行身份验证,检索用户对象和会话数据,然后从服务模块获取CSRF令牌。我遇到的问题是在标题中设置所有这些,以便后续请求被验证。我理解整体概念,但对AngularJS和新的CSRF攻击都是新手。
从我收集到的有关使用AngularJS和RubyOnRails的这个设置的阅读中,平台之间可能存在关于令牌的命名及其处理方式的不一致。关于如何在标题中设置此标记似乎也有很多建议。但是,我很难找到一个如何使这些平台使用相同语言的可靠示例。
我在app.js中使用$ httpProvider做的唯一事情就是:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
登录控制器,在controller.js中:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
答案 0 :(得分:3)
解决方案与如何设置cookie然后传递后续请求有关。尝试手动设置它们并不顺利,但解决方案比我预期的要简单。每个$ http调用都需要设置选项:
withCredentials: true
我做的另一个改变是使用术语CSRF而不是XSRF,以与Drupal保持一致。我没有使用任何内置的AngularJS CSRF功能。
答案 1 :(得分:2)
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
因为这个话题已经有一年了!不确定仍然遇到同样的问题,但对于那些来寻找答案的人是我如何处理它! 注意标题{}部分我定义一个新标题并将其称为X-CSRF-Token并从(serverside)生成的html或php的DOM中获取值。从服务器请求csrf令牌也不是一个好习惯.Cuz攻击者也可能以某种方式请求它。因为您将其保存为cookie。攻击者可以偷走cookie!无需将其保存在cookie中!发送带有标头的令牌并在服务器端读取它以匹配它!
和同一页面问题的multitab。我在整个会话期间使用相同的标记。 仅在登录,注销和更改主要站点或用户设置时重新生成。
答案 2 :(得分:2)
有一个很棒的图书馆呼叫ng-drupal-7-services。如果您在项目中使用它,它将解决验证/重新验证和文件/节点创建的问题,并且您可以了解项目中的重要内容。
所以身份验证就像这样解决了:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
这个项目还有一些厨房水槽:Drupal-API-Explorer
答案 3 :(得分:0)
是的,每个平台都有自己的约定命名约定。
这是一个小型的lib放在一起,希望能够轻松使用不同的平台。这将允许您使用集名称,并可用于所有请求。它也适用于跨域请求。