Я хочу отправить подлинный маркер при запросе ресурса от моего API.
Я действительно реализовывал сервис с помощью $resource:
factory('Todo', ['$resource', function($resource) {
return $resource('http://localhost:port/todos.json', {port:":3001"} , {
query: {method: 'GET', isArray: true}
});
}])
И у меня есть сервис, который хранит подлинный маркер:
factory('TokenHandler', function() {
var tokenHandler = {};
var token = "none";
tokenHandler.set = function( newToken ) {
token = newToken;
};
tokenHandler.get = function() {
return token;
};
return tokenHandler;
});
Я хотел бы отправить маркер от tokenHandler.get
с каждым запросом отправляют через Todo
сервис. Я смог отправить его путем помещения его в вызов определенного действия. Например, это работает:
Todo.query( {access_token : tokenHandler.get()} );
Но я предпочел бы определять access_token в качестве параметра в Todo
сервис, когда это должно быть отправлено с каждым вызовом. И улучшить DRY. Но все на фабрике выполняется только однажды, таким образом, access_token должен был бы быть доступным прежде, чем определить фабрику и ее изменение наклона впоследствии.
Существует ли способ поместить динамично обновленный параметр запроса в сервис?
Другое решение состояло бы в том, чтобы использовать resource.bind (additionalParamDefaults), тот возврат новый экземпляр ресурса, связанного с дополнительными параметрами
var myResource = $resource(url, {id: '@_id'});
var myResourceProtectedByToken = myResource.bind({ access_token : function(){
return tokenHandler.get();
}});
return myResourceProtectedByToken;
, функция access_token будет вызвана каждый раз, когда любое действие с ресурсом называют.
После Вашего принятого ответа я предложил бы расширить ресурс для установки маркера с объектом Todo:
.factory('Todo', ['$resource', 'TokenHandler', function($resource, tokenHandler) {
var resource = $resource('http://localhost:port/todos/:id', {
port:":3001",
id:'@id'
}, {
update: {method: 'PUT'}
});
resource = tokenHandler.wrapActions( resource, ["query", "update"] );
resource.prototype.setToken = function setTodoToken(newToken) {
tokenHandler.set(newToken);
};
return resource;
}]);
Таким образом нет никакой потребности импортировать TokenHandler каждый раз, когда Вы хотите использовать объект Todo, и можно использовать:
todo.setToken(theNewToken);
Другое изменение, которое я сделал бы, состоит в том, чтобы позволить действия по умолчанию, если они пусты в wrapActions
:
if (!actions || actions.length === 0) {
actions = [];
for (i in resource) {
if (i !== 'bind') {
actions.push(i);
}
}
}
Иначе должен использовать перехватчик HTTP, который заменяет "волшебный" заголовок Авторизации текущим маркером OAuth. Кодом ниже является конкретный OAuth, но исправление, которое является простым осуществлением для читателя.
// Injects an HTTP interceptor that replaces a "Bearer" authorization header
// with the current Bearer token.
module.factory('oauthHttpInterceptor', function (OAuth) {
return {
request: function (config) {
// This is just example logic, you could check the URL (for example)
if (config.headers.Authorization === 'Bearer') {
config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
}
return config;
}
};
});
module.config(function ($httpProvider) {
$httpProvider.interceptors.push('oauthHttpInterceptor');
});
Я должен был иметь дело с этой проблемой также. Я не думаю, является ли это изящное решение, но это работает и существует 2 строки кода:
я предполагаю, что Вы получаете свой маркер от Вашего сервера после аутентификации в SessionService, например. Затем назовите этот вид метода:
angular.module('xxx.sessionService', ['ngResource']).
factory('SessionService', function( $http, $rootScope) {
//...
function setHttpProviderCommonHeaderToken(token){
$http.defaults.headers.common['X-AUTH-TOKEN'] = token;
}
});
После этого все Ваши запросы от $resource и $http будут иметь маркер в своем заголовке.
Мне действительно нравится этот подход:
http://blog.brunoscopelliti.com/authentication-to-a-restful-web-service-in-an-angularjs-web-app
, куда маркер всегда автоволшебно отправляется в заголовке запроса без потребности обертки.
// Define a new http header
$http.defaults.headers.common['auth-token'] = 'C3PO R2D2';