I have a basic angular APP that makes a GET request call to a API URL. The data returned is in JSON format. The API documentation states the following:
You must provide your App ID and key with every request that you make to the API. To do this, set an HTTP Authorization header on your requests that consists of your ID, followed by a colon, followed by your key, eg abc123:xyz789.
How do I incorporate this to my basic HTTP request.my code is below.
angular.module('myApp', [])
.controller('MyControler', function($scope, $http) {
$scope.$watch('search', function() {
fetch();
});
$scope.search = "My Search Query";
function fetch() {
$http.get("https://APIURlGoesHere" + $scope.search )
.then(function(response) {
$scope.details = response.data;
});
$http.get("ttps://APIURlGoesHere" + $scope.search)
.then(function(response) {
$scope.related = response.data;
});
}
});
Best way I know so far to implement this is: Interceptors
You can find some useful info about it here and here
And on SO, here: AngularJS $http interceptors
In your case, basically, you need to create a file with the following implementation (or equivalent) and include it into your project:
function myInterceptor() {
function request(req) {
var token = "mytoken" ; //<<--here you need to set the custom header's info (eg: abc123:xyz789)
var myHeader = "myHeader"; //<<--here you need to set the custom header's name (eg: Authorization)
if (token) {
//put custom header for sending the token along with every request
req.headers[myHeader] = token;
}
return req;
}
return {
request: request
};
};
function conf($httpProvider) {
$httpProvider['interceptors'].push('myInterceptor');
};
angular
.module('your_module_name')
.factory('myInterceptor', myInterceptor)
.config(['$httpProvider', conf]);
This will intercept every request made from your frontend app and will include that header on it.
Citing this topic:
How to use Basic Auth with jQuery and AJAX?
So, in Angular, it would be:
$http({
method: "GET",
url: "https://APIURlGoesHere" + $scope.search,
headers: { 'Authorization' : 'Basic '+btoa(username + ":" + password)
})
.then(function(response) {
$scope.details = response.data;
});
Related
Hi I am developing web application in angularjs. I am making lot of http calls to interact with web api. As a result i have to send lot of data in headers too. I have created factory for get data as below. These data should should be passed in headers. Below is my factory.
var myapp = angular.module('RoslpApp');
myapp.factory("ScrollFunction", ['$location', '$anchorScroll', '$cookieStore', function ($location, $anchorScroll, $cookieStore) {
return {
getheaders: function () {
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
var headers={
Logintoken: $cookieStore.get('LoginToken'),
LoginId: $cookieStore.get('LoginID'),
RequestedPlatform: "Web",
RequestedLanguage: cookiePreferredLanguage
};
return headers;
}
}
}
]);
Below is my sample http call.
function getpermissiondetails() {
var headersdata = ScrollFunction.getheaders();
$scope.Create = "Create";
var getsavedvechilceUrl = baseurl + "api/RolesPermission/getgroups";
var request = {
url: getsavedvechilceUrl,
method: 'GET',
headers: {
RequestedPlatform: headersdata.RequestedPlatform,
RequestedLanguage: headersdata.RequestedLanguage,
Logintoken: headersdata.LoginToken,
LoginId: headersdata.LoginID
}
};
$http(request).then(function (response) {
$scope.groups = response.data.data;
}, function (error) {
})
}
What i want in header is i already have data in var headersdata = ScrollFunction.getheaders(); Is it possible to pass something like headers: { headersdata } because i can make add headers in factory. No need to expand it in each http call. I tried headers: { headersdata } but this is not sending any data to api. May i know is there any better solution? Any help would be appreciated. Thank you.
I guess this is a code refractoring question.
Q: Can I avoid doing the messy property assignment by doing something shortcut like headers={ factory data }?
A: Ok. I probably did a bad job paraphrasing your question. I'm just trying to make it more understandable.
Short answer: Yes. You can further shorten your code by doing this.
var request = {
url: getsavedvechilceUrl,
method: 'GET',
headers: ScrollFunction.getheaders()
};
Why?
Your function getheaders() is already returning a javascript object which is exactly what request.headers is looking. An object {}.
Since getHeaders() is already returning an object you can just plug it straight into request.headers. That is, you no need to re-create an object and reassign the property back in one by one.
Hope this helps.
I have this $http request interceptor
app.config(function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
request: function(req) {
// Set the `Authorization` header for every outgoing HTTP request
req.headers['cdt_app_header'] = 'tamales';
return req;
}
};
});
});
Is there any way we can add a header or cookie to every $http request, but keep the header value secure / not visible with JavaScript?
We can add an obfuscation layer with this header to prevent easy access to our API endpoints, but I am wondering about a more truly secure solution.
Cookies are used for secure sessions, and these are more secure because they cannot be accessed with JavaScript. Say we have a user who can do this request with front-end code:
GET /api/users
we don't really want them to be able to make a simple request with cURL or a browser without an extra piece of information. The cookie we give them will give them the ability to use the browser address bar to make a GET request to /api/users, but if we add the requirement to have another cookie or header in place, then we can prevent them from accessing endpoints that are authorized for, in a format that we don't really want them to use.
In other words, we want to do our best to give them access, but only in the context of a front-end Angular app.
I can't add a comment because of my rep but what are you doing on the back-end to authorize users? If the cookie is signed and contains user permissions it shouldn't matter that the header is visible in the client as it will also be verified on the back-end API call.
in this sample i used HttpRestService to get RESTful API, read this article
at first we create a service to get our configs in this sample is getConfigs
we use getConfigs in the app.run when application is started, after get the configs we set them all in the header as sample.
after that we can get userProfile with new header and also secure by call it from our controller as you see.
in this sample you need to define apiUrl, it's your api host url, remember after logout you can remove the header, also you can define your configs dynamically to make more secure for your application.
HttpRestService.js github link
app.js
var app = angular.module("app", ["HttpRestApp"]);
app.service
app.service("service", ["$http", "$q", "RestService", function (http, q, restService) {
this.getConfigs = function () {
var deferred = q.defer();
http({
method: "GET",
async: true,
headers: {
"Content-Type": "application/json"
},
url: "you url to get configs"
}).then(function (response) {
deferred.resolve(response.data);
}, function (error) {
deferred.resolve(error);
});
return deferred.promise;
}
var api = {
user: "User" //this mean UserController
}
//get user with new header
//this hint to your api with this model "public Get(int id){ return data; }"
//http://localhost:3000/api/users/123456
this.getUserProfile= function(params, then) {
restService.get(params, api.user, true).then(then);
}
}]);
app.run
app.run(["RestService", "service", function (restService, service) {
var header = {
"Content-Type": "application/json"
}
//get your configs and set all in the header
service.getConfigs().then(function (configs) {
header["systemId"] = configs.systemId;
});
var apiUrl = "http://localhost:3000/";
restService.setBaseUrl(apiUrl, header);
}]);
app.controller
app.controller("ctrl", ["$scope", "service", function ($scope, service) {
$scope.getUserProfile = function () {
//this is just sample
service.getUserProfile({ id: 123456 }, function (data) {
$scope.user = data;
});
}
$scope.getUserProfile();
}]);
I am creating an login page using Angular. After I process my login in the backend, I set the values in MyService from my LoginCtrl and then move to the next page using $window.location.href= 'main.jsp'; . But when I call the values which I set in LoginCtrl from HomeCtrl, the values are empty?
I know that Services are singletons and will maintain the same state throughout the app. But in this case, It jut resets. I think it is because of using $window.location.href. Please help me solve my problem.
This is my service ( MyService ):
app.service('MyService', function() {
var user = {
name: '',
permissions: ''
};
this.getUser = function() {
return user;
}
this.setUser = function(userr) {
this.user = userr;
}
});
This my LoginCtrl: ( I've just posted the http.post part)
$http({
method: 'POST',
url: 'login',
data: JSON.stringify($scope.user),
headers: {
'Content-Type': 'application/json'
}
}).success(function(data) {
if (!("failure" == data)) {
console.log(data);
var user = MyService.getUser();
user.name = data.name;
user.permissions = data.permissions;
console.log(user);
console.log(MyService.getUser());
$window.location.href = 'main.jsp';
// MyService.changeLocation('main.jsp', true);
} else {
$scope.information = "Invalid username/password!"
}
}).error(function(data) {
console.log(data);
});
And this is my HomeCtrl:
app.controller('HomeCtrl', function($scope, $http,MyService) {
console.log(MyService.getUser());
var user = MyService.getUser();
$scope.flashMessage="Hello " + user.name;
});
Here user.name is empty.
You are changing your web page. The angular application is not persisted across the website boundary; remove the alteration to the window.location.href.
In order to simulate page changing in Angular consider using the official router (shipped with Angular 1.4+), ngRoute or Angular UI Router. These solutions use the HTML History Api and fallback to hashbang URLs to emulate the sort of thing you're trying to achieve.
This ends up creating a single-page application, which is what Angular is designed for.
In LoginCtrl, while reaching the success callback, you are not setting the response value(data in your case) to user object in MyService service.
You are getting the user object from the Service by
var user = MyService.getUser();
But setting the values to that object will not set the user object in the Service.
You need to use MyService.getUser(user); to set values in your service and the same will be available in your HomeCtrl
$http({
method: 'POST',
url: 'login',
data: JSON.stringify($scope.user),
headers: {
'Content-Type': 'application/json'
}
}).success(function(data) {
if (!("failure" == data)) {
console.log(data);
var user= {};
user.name = data.name;
user.permissions = data.permissions;
MyService.getUser(user); //set the values for user
var obj= MyService.getUser(); //get the values for user
console.log(obj);
//should display user object
//with respective name and permissions should be available
console.log(MyService.getUser());
$window.location.href = 'main.jsp';
// MyService.changeLocation('main.jsp', true);
} else {
$scope.information = "Invalid username/password!"
}
}).error(function(data) {
console.log(data);
});
UPDATE:
The reason why your code doesnt seem to work is: you are using $window incorrectly to change the route. $window.location.href = 'main.html' is somehow changing the route outside angular's context and hence not running the HomeCtrl. To fix this, you need to do the following:
First, define routes for your angular application (preferabbly using ui-router)
app.config(function($stateProvider){
$stateProvider
.state('login',{
url:'/',
templateUrl:'login.html',
controller:'LoginCtrl'
})
.state('main',{
url:'/main',
templateUrl:'main.html',
controller:'HomeCtrl'
})
.state("otherwise", { url : '/'})
})
Use $location.url('/main'). Notice it is same as the url pattern we defined for state: main. Or better, you should use $state.go('home'); to redirect the user to desirable state
Here's a working plunkr
Hope this helps!
I built a small API for my ecommerce application (built in Laravel) so I could use it with a frontend I built in Angular. I put the API on a subdomain and added the Access-Control-Allow-Origin Header to allow calls from the api origin.
The problem is that Angular seems to be stripping out all headers from the request so it never sees my CORS header. My REST API client sees the header correctly. I tried using a basic XMLHttpRequest and it sees the header correctly. But inside Angular, looking at the response from $http.get(), I can't see the CORS header, or any other header I've tried.
Here's what my service looks like:
angular.module('SFAdmin').factory('Category', function($http){
$http.defaults.useXDomain = true;
var baseUrl = 'http://api.example.com/categories';
return {
query: function(){
return $http.get(baseUrl);
},
get: function(id){
return $http.get(baseUrl + '/' + id);
},
create: function(data){
return $http.post(baseUrl, data);
},
update: function(data){
return $http.put(baseUrl + data.id, data);
},
delete: function(id){
return $http.delete(baseUrl + '/' + id);
},
trash: function(){
return $http.get(baseUrl + '/trash');
}
}
});
My Category controller:
angular.module('SFAdmin').controller('CategoriesIndexController', function(Category, $scope, $location){
Category.query().success(function(data){
$scope.categories = data;
}).error(function(d, s, h){
console.log(d, s, h());
});
});
And my api route is sending this:
$app->get('/categories/', function(){
$content = (new App\Http\Controllers\CategoryController())->index(); // index() gets all categories.
return response($content)
->header('Access-Control-Allow-Origin', '*');
});
How do I get Angular to view incoming headers correctly?
I'm using AngularJS to login a user (using Restangular). The login controller gets returned a 'Token' which I then need to use on every request thereafter.
My question is, what is the best way to store this Token using AngularJS? It needs to exist for the lifetime of the app.
I was looking at services but I have to keep injecting it into the controllers on to keep it alive.
lifetime is not promise as far as you are using web apps, but if you want you can use localstorage,
here is an example service how to use localstorage in angular, you can add it to service.js file:
var storeService = innovidServices.factory('storeService', function() {
var service =
{
setClientData:function(client_details)
{
window.localStorage.setItem( "client_data", JSON.stringify(client_details) );
client_data = client_details;
},
getClientData:function()
{
if (client_data == null)
{
client_data = JSON.parse(window.localStorage.getItem("client_data"));
}
return client_data;
}
}
var client_data = null;
return service;
});
I think the best way is store this 'Token' in the $rootScope.
myapp.controller('loginCtrl', function($scope, $rootScope) {
...
$rootScope.token = Token;
...
});
Then use http interceptor to inject this as for example GET parameter to every query
myapp.factory('httpTokenInterceptor', function ($rootScope) {
return {
request: function (config) {
var token = $rootScope.token;
if (token) {
config.url = URI(config.url).addSearch({'token':token}).toString();
}
return config;
}
};
});
myapp.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpTokenInterceptor');
});