I have a problem and don´t know how to solve it...
I have to authenticate a user in my IonicApp through a token based authentication. So i have to store the token inside the app, which shouldn´t be a problem...
The Problem is: How can i get the token?
Here´s my code:
// Alle Aufrufe an die REST-Api werden hier durchgeführt
var httpCall = {
async : function(method, url, header, params, data) {
// if (url != 'login') {
// header['X-Auth-Token'] = userTokenFactory.getUserToken();
// }
//console.log(header['X-Auth-Token']);
var ipurl = "IPURL";
// $http returns a promise, which has a then function, which also returns a promise
var promise = $http({
method : method,
url : ipurl + url,
//headers : header,
params : params,
data : data,
config : {
timeout : 5000
}
}).then(function successCallback(response) {
//console.log("data:" + response.data);
//console.log("header:" + response.headers);
console.log("token:" + response.headers['X-AUTH-TOKEN']);
//console.log(response.data.token);
console.log("token" + repsonse.token);
// TRY TO READ THE X_AUTH_TOKEN HERE !!!!!!!!!!!!
return response;
}, function errorCallback(response) {
return response;
});
// Return the promise to the controller
return promise;
}
};
return httpCall;
});
And here´s a picture of the Response from the Server (from Firefox). As you can see, the X-Auth-Token is there...
here´s the x-auth-token
Thanks for the help!!
There are lot of articles are available over handling authentication in AngularJS. This article is the one perfect suitable in your case.
So you can get token from your request as,
}).then(function successCallback(response) {
console.log("data:" + response.data);
$window.sessionStorage.token = response.data.token;
return response;
}, function errorCallback(response) {
return response;
});
Now we have the token saved in sessionStorage. This token can be sent back with each request by at least three ways
1. Set header in each request:
`$http({method: 'GET', url: url, headers: {
'Authorization': 'Bearer ' + $window.sessionStorage.token}
});`
2. Setting defaults headers
`$http.defaults.headers.common['X-Auth-Token'] = 'Bearer ' + $window.sessionStorage.token;`
3. Write Interceptor:
Interceptors give ability to intercept requests before they are
handed to the server and responses before they are handed over to the
application code that initiated these requests
myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
myApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Refer AngularJS $http guide for detailed explanation.
As you are getting response.data null and image demonstrates that headers are being returned, I would suggest you to check if you are getting data with
response.headers(),
if then try with response.headers()["X_AUTH_TOKEN"].
Related
I have an issue at the moment with the google url shortener.
I have set up this service:
angular.module('widget.core').service('urlShortener', service);
function service($log, $q, $http) {
var gapiKey = '<MyApiKey>';
var gapiUrl = 'https://www.googleapis.com/urlshortener/v1/url';
return {
shorten: shorten
};
//////////////////////////////////////////////////
function shorten(url) {
console.log(url);
var data = {
method: 'POST',
url: gapiUrl + '?key=' + gapiKey,
headers: {
'Content-Type': 'application/json',
},
data: {
longUrl: url,
}
};
return $http(data).then(function (response) {
$log.debug(response);
return response.data;
}, function (response) {
$log.debug(response);
return response.data;
});
};
};
As far as I can tell, this should work. I have put in the correct API key and when I run this method I get this error:
{
error: {
code: 401,
message: 'Invalid credentials'
}
}
But, if I use postman and set it up exactly like this method:
Make it post
Add the content-type header and set it to application/json
set the url to https://www.googleapis.com/urlshortener/v1/url?key=myapikey
set the body to:
{
longUrl: 'myreallylogurl.com'
}
When I post this, it works with no issues.
I have checked my application on the google console and it is definitely set to unrestricted.
Has anyone come across this issue before? Does anyone know how to solve it?
I figured this out, it was nothing to do with the code above, but I thought I would answer my own question because someone else may run into the same issue.
In the project I have an httpInterceptor set up that adds the authetentication token to each request for talking to my API. This was what was causing the issue.
It so happened that I already defined a constant for my apiUrl, so I just updated the interceptor to check to make sure that the request url was my api before trying to append the token.
Like this:
angular.module('widget.core').factory('authInterceptor', factory);
function factory($q, $location, $localStorage, apiUrl) {
// The request function
var request = function (config) {
// If we are querying our API
if (config.url.indexOf(apiUrl) > -1) {
// Get our stored auth data
var authData = angular.fromJson($localStorage.get('authorizationData'));
// Set our headers to the request headers or a new object
config.headers = config.headers || {};
// If we have any auth data
if (authData && authData.authenticated) {
// Set our authorization header
config.headers.Authorization = 'Bearer ' + authData.token;
}
}
// Return our config
return config;
};
return {
request: request
};
};
I hope that helps someone else. Took me hours to figure it out :/
I'm trying to add the 'Authorization' header containing a token for future HTTP request. Retrieval of the token seems to be fine however when making a get request it fails with an Unauthorized error message. After checking the request headers Authorization header does not exist in the request block...
window.crUtil = /*window.crUtil ||*/ (function() {
// Angular Services
var $injector = angular.injector(['ng']);
var $http = $injector.get('$http');
// getting the CFF data
function get_data() {
getJWTAWS();
var url = '/AWS/getDATA/555';
console.log('AUTH header before call: ' + $http.defaults.headers.common.Authorization);
$http.get(url,httpHeader).then(function successCallback(response) {
var data = response.data;
var cff = initCff();
alert(data.itemId);
}, function errorCallback(response) {
initCff();
alert("Error while getting data ");
});
}
function getJWTAWS() {
var httpConfig = {
cache: true,
params: {}
};
$http.get('/AWS/token', httpConfig).then(
function(response) {
if (response.data.accessToken) {
// add jwt token to auth header for all requests made by the $http service
$http.defaults.headers.common.Authorization = response.data.tokenType + ' ' + response.data.accessToken;
}
},
function(error) {
alert('jwt token could not be retrieved.');
}
);
}
})();
var result = util.get_data();
console.log ('called search function ' + result);
Function getToken() returns a value but as I'm new on that topic I'm not quite sure if the way I added the token to the headers is proper.
Could you please advise on the proper way to include the headers in the request. I also tried to add it to the get request like
$http.get(URL,httpHeaders)...
but it also didn't work.
I'm not sure I understand your problem completely as you did not provide what you call
httpConfig
If you're struggling to declare the headers, try making the get request like this:
$http({
method: 'GET',
url: YOUR_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': AUTH_STRING_HERE
}
}).then(function (response) { ... });
You can add any headers you like in the headers object there.
Try adding this in your config block and set the token in your rootscope
$httpProvider.interceptors.push({
request: function (config) {
config.headers.Authorization = $rootScope.token;
return config;
}
})
I'm new angularJS student, and i want to get detail error's when i send a POST to WebApi.
I want to get Status 500 and Status 404, and make condition to show a feedback instead of the status error.
I have tried use "Intercepting HTTP calls with AngularJS", but everytime it returns 'Status -1'
Can anyone help me please?
Thanks!
#EDIT
.factory('ajaxFn', function ($http, $cookies, $location, $q) {
var post = function (url, objeto, data, successFn, errorFn) {
user = $cookies.get(btoa('user'));
pass = $cookies.get(btoa('pass'));
authHeader.Authorization = 'Basic ' + btoa(user + ':' + pass);
$http({
method: 'POST',
url: "//localhost:61115/api/main/" + CompleteUrl,
headers: authHeader,
params: objeto,
data: data
})
.then(function (result) {
successFn(result.data);
}, function (data) {
errorFn();
});
}
return {
post: post
};
})
And that is the intercepting code that i have tried
// Intercepting HTTP calls with AngularJS.
.config(function ($provide, $httpProvider) {
// Intercept http calls.
$provide.factory('MyHttpInterceptor', function ($q) {
return {
// On request success
request: function (config) {
// console.log(config); // Contains the data about the request before it is sent.
// Return the config or wrap it in a promise if blank.
return config || $q.when(config);
},
// On request failure
requestError: function (rejection) {
// console.log(rejection); // Contains the data about the error on the request.
// Return the promise rejection.
return $q.reject(rejection);
},
// On response success
response: function (response) {
// console.log(response); // Contains the data from the response.
// Return the response or promise.
return response || $q.when(response);
},
// On response failture
responseError: function (rejection) {
// console.log(rejection); // Contains the data about the error.
// Return the promise rejection.
return $q.reject(rejection);
}
};
});
// Add the interceptor to the $httpProvider.
$httpProvider.interceptors.push('MyHttpInterceptor');
})
I have a service that returns a promise.
function GetSuggestedPeersService($http, SITE_CONFIG) {
var getSuggestedPeersService = this;
var data;
getSuggestedPeersService.getSuggestedPeersList = function() {
var baseUrl = SITE_CONFIG.baseUrl + "fetchSuggestedPeers";
var response = $http({
method : 'POST',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
}
getSuggestedPeersService.setSuggestedPeers = function(suggestedPeers) {
getSuggestedPeersService.suggestedPeers = suggestedPeers;
}
getSuggestedPeersService.getSuggestedPeers = function() {
return getSuggestedPeersService.suggestedPeers;
}
}
Now I use the following in the Controller to resolve the promise:
//gets the suggested peers
var promiseSuggestedPeers = GetSuggestedPeersService.getSuggestedPeersList();
promiseSuggestedPeers.then(function (response) {
peerHealthController.GetSuggPeersShow = response.data;
GetSuggestedPeersService.setSuggestedPeers(peerHealthController.GetSuggPeersShow);
return peerHealthController.GetSuggPeersShow;
})
.catch(function (error) {
console.log("Something went terribly wrong Suggested Peers.");
});
Now my question is call this service multiple times and need to update this on other service calls as well.
What is the best way to write the controller part so as not to repeat the resolve promise every time I call the service?
It's been long time.
But I just wanted to answer this question.
The best way to design this would be to use a factory. So this will become a reusable service.
An example code can be the following:
var httpMethods = peerHealthApp.factory('HttpService',HttpService);
httpMethods.$inject = ['$http', 'SITE_CONFIG'];
function HttpService($http, SITE_CONFIG){
console.log("SITE_CONFIG from Peer Service: " + SITE_CONFIG);
var factory = {
httpGet : function(relativePath,data){
var baseUrl = SITE_CONFIG.baseUrl + relativePath;
var response = $http({
method : 'GET',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
},
httpPost : function(relativePath, data){
var baseUrl = SITE_CONFIG.baseUrl + relativePath;
var response = $http({
method : 'POST',
url : baseUrl,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
data : data
});
return response;
}
};
return factory;
}
And the above can be used again and again like the following:
var data=$.param({
"url":moderatedArticleLink
});
var promiseURLMetaData = HttpService.httpPost("parseUrlMetadata", data);
promiseURLMetaData.then(function (response) {
var urlMetaData = response.data;
return urlMetaData;
})
.catch(function (error) {
console.log("Something went terribly wrong while trying to get URL Meta Data.");
});
What is the best way to write the controller part so as not to repeat the resolve promise every time I call the service?
Instead of saving the data in a service, I recommend saving the promise:
if ( !Service.get() ) {
var promise = Service.fetch();
Service.set(promise);
});
Service.get().then(function (response) {
$scope.data = response.data;
}).catch( function(errorResponse) {
console.log(errorResponse.status);
throw errorResponse;
});
By checking for the promise and only fetching if necessary, multiple controllers can share the data without caring about the order of controller instantiation. This avoids race conditions and multiple XHRs to the same resource.
I'm having troubles with $http calls in AngularJS. I've created the following services
crApp.service('authService', function ($http) {
var urlBase = 'http://192.168.xx.xx:8081';
// POST api/login/
this.login = function (credentials) {
return $http.post(urlBase + "/api/login", credentials);
};
// POST api/logout/
this.logout = function () {
return $http.post(urlBase + "/api/logout/", "");
};
}); //end service
crApp.service('dataService', function ($http) {
var urlBase = 'http://192.168.xx.xx:8081';
// POST api/query/
this.pull = function (query) {
return $http.post(urlBase + "/api/query", query);
};
From the controller I call the login method:
$scope.login = function(){
authService.login(credentials)
.success(function(data) {
console.log("RESULT LOGIN: " + data );
})
.error(function(data, status, headers, config) {
console.log(data);
console.log(status);
console.log(headers);
console.log(config);
});
};
So far so good and I receive a response where a cookie is set:
After succesfull login I call the following method:
var locations = { query: "from location select uid, name, description, address, phone", dataFormat: "verbose" };
$scope.getLocations = function() {
dataService.pull(portals)
.success(function (data) {
console.log("RESULT QUERY: " + data)
})
.error(function(data, status, headers, config) {
console.log("Query niet gelukt!");
console.log(data);
console.log(status);
console.log(headers);
console.log(config);
});
};
Result:
So cookie is not set in the headers.
I'm using AngularJS 1.3.15 and calls are made to a remote server on a different domain, but it does work in the REST Client tool in WebStorm (Jetbrains). So it must be something i'm missing in Angular!??
Hopefully someone can help me out.
You need to set withCredentials = true in the $http config to allow cookies to be set on CORS requests. This article explains more about cookies and CORS.
In your app config:
$httpProvider.defaults.withCredentials = true;
For example:
angular.module('myApp', [])
.config(['$httpProvider'){
$httpProvider.defaults.withCredentials = true;
}]);
You can read about this option in the $http provider documentation.