i have try to access(get request) my laravel api from ionic(angularjs) app.
but it keep getting bellow error.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL
please help me to fix this
This response is based on the fact that it appears you have control of serve-side code.
Have you added CORS support to the response? If you have not done so it could be like this.
You could add a handler thus:
Route::head("/<path to resource>", function () {
$r = Response::make("hello");
//Access-Control-Allow-Origin: http://api.bob.com
// Access-Control-Allow-Credentials: true
$r->header("Access-Control-Allow-Origin", "<*|client request domain>")
->("Access-Control-Allow-Credentials", "true")
->("Access-Control-Request-Method", "GET");
});
Perhaps you could set this headers on the response you are sending itself, I'm not sure. If that is possible and you might use this sort of thing on several routes it's better you prepare it as a filter. You can read more on CORS at http://www.html5rocks.com/en/tutorials/cors/ .
If what you want to send is json data think about serving your response to support jsonp. You could do something like:
$normalData = Model::all();
// if the client made a jsonp style request
if (Input::has("callback")) {
$data = "<script>" . Input::get("callback") . "(" . json_encode($normalData) . ")";
return Response::make($data)->header("Content-Type", "appplication/javascript");
}else {
//if not then return normally
return Response::json($normalData);
}
You are trying to access api from one domain to a different domain.
There are many ways to overcome this issue,but since it is a get Request,use **jsonp*.
Try something like this
var url = ' http://128.xxx.xxx.xx/mobi/check/?username=achchu&apikey=1N7GyYRfq8bQnrFCCGgL&callback=JSON_CALLBACK';
$http.jsonp(url)
.success(function(data) {
});
Related
I am currently building an application using token based authentication with Angular and Laravel. I initially set things up just to test the API by creating a BookController . At first I was getting a Cross Origin Request Block error when I tried to call this data from Angular. However I managed to resolve this by adding the headers to my routes/web.php file. Here is the whole file. NB: After adding these headers I was succesfully able to use the API even from another domain
<?php
header('Access-Control-Allow-Origin: *');
header( 'Access-Control-Allow-Headers: Authorization, Content-Type' );
//Route::get('/', 'BookController#show');
//Route::resource('book/create', 'BookController#create');
Auth::routes();
Route::get('/', 'HomeController#index');
Route::resource('book', 'BookController');
Route::resource('authenticate', 'AuthenticateController', ['only' => ['index']]);
Route::post('authenticate', 'AuthenticateController#authenticate');
However I am currently following this tutorial to set up token based authentication. https://scotch.io/tutorials/token-based-authentication-for-angularjs-and-laravel-apps
To summarise , my issue is when I submit the form containing username and password I am getting the following errors. Below I will try elaborate a bit more but it is quite difficult as there is alot to it.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://www.example.local/authenticate/.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).
And
Possibly unhandled rejection:
{"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://www.example.local/authenticate/","data":{"email":"dasdas#Dasa.com","password":"fsdfd"},"withCredentials":false,"headers":{"Accept":"application/json,
text/plain,
/","Content-Type":"application/json;charset=utf-8"}},"statusText":""}
I am using Angular UI Router V 0.4.2 and satellizer. My Angular version is 1.6.2 It using a different domain than the API. Much like the working example above.
On the laravel side I also followed this tutorial to add middleware to attempt to resolve this but no luck.
http://en.vedovelli.com.br/2015/web-development/Laravel-5-1-enable-CORS/
I will also include my AuthenticateController.php file..
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use App\User;
class AuthenticateController extends Controller
{
public function __construct()
{
// Apply the jwt.auth middleware to all methods in this controller
// except for the authenticate method. We don't want to prevent
// the user from retrieving their token if they don't already have it
$this->middleware('jwt.auth', ['except' => ['authenticate']]);
$this->middleware('cors');
}
public function index()
{
// Retrieve all the users in the database and return them
$users = User::all();
return $users;
}
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
try {
// verify the credentials and create a token for the user
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
}
My issue is I do not even know if the "possibly unhandled rejection" is related to the "Cross-Origin Request Blocked" error. But I have to assume it is.
Can you recognise anything from my routes files that may be allowing one and not another?
EDIT:
I have noticed the difference between one request and another is that one is a GET request while another is an OPTIONS request. This may be the cause.
I have since added Header set Access-Control-Allow-Origin "*" to both the virtual hosts config file in Apache and to a .htaccess file in the root of the Laravel project. Still no change.
I am wondering is this related something in Angular
Your server code needs to handle that OPTIONS request by sending a headers-only response to it that includes the Access-Control-Allow-Methods: GET, POST, PUT, DELETE header and Access-Control-Allow-Headers: Authorization, Content-Type header.
Or you can just try using https://github.com/barryvdh/laravel-cors which makes all this easier.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests has general info you might want to read up on.
i am new to this and i am trying to login and get a token so the ionic and laravel can communicate. I am using satellizer and jwt on laravel. on post man i get the token back:
this is what i am getting loging in from ionic:
[enter image description here][2]
the error says:
XMLHttpRequest cannot load http://localhost:8000/api/authenticate. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access.
and yeah, on my laravel side, i have included
header("Access-Control-Allow-Origin: *");
what am i missing here, thank you
There are many factors to why this happens. the error may happen because you have no access headers and the browsers gets this and blocks your requests.
It also happens when you your server experiences internal errors like 500,403,401 etc. you may have added headers to the requests life cycle(like in the middleware to filter all api requests) in your laravel app but sometimes an error 500 or even an echo or dd() interrupts the whole request life cycle and returns the errors WHICH the browser can't interpret through an ajax call and therefore it loses the headers you implicitly added thus the browser goes back to the preflight request error..
The only solution I suggest is proper error handling in your code and returning errors in a response and return it in json format.
public function someController extends Controller{
public function Foo(Request $request){
$input_bag = [
'some input' => first_$input,
'another important input' => $second_input,
];
$i = 0;
foreach ($input_bag as $key => $value) {
$value = trim($value);
if (empty($value)) {
$error_bag[$i] = "$key empty";
$i++;
} else {
//
}
}
//filter of false or null values
if (array_filter($error_bag)) {
return response()->json($error_bag, 400);
}
}
this returns a json response of the errors while running the code. and good use of try catches and returning the appropriate responses could make your debugging life easy.
I'm new to Single Page Application area and I try to develop app using angularjs and Spark framework. I get error 400 bad request when I want to post JSON from my website. Here is code fragment from client side:
app.controller('PostTripCtrl', function($scope, $http) {
$scope.newTrip = {};
$scope.submitForm = function() {
$http({
method : 'POST',
url : 'http://localhost:4567/trips/add',
data : $scope.newTrip,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
}
}).success(function(data) {
console.log("ok");
}).error(function(data) {
console.log("error");
console.log($scope.newTrip);
});
};
});
Values that are to be assigned to newTrip are read from appropriate inputs in html file. Here is server-side fragment:
post("/trips/add", (req, res) -> {
String tripOwner = req.queryParams("tripOwner");
String startDate = req.queryParams("startDate");
String startingPlace = req.queryParams("startingPlace");
String tripDestination = req.queryParams("tripDestination");
int tripPrice = Integer.parseInt(req.queryParams("tripPrice"));
int maxNumberOfSeats = Integer.parseInt(req.queryParams("maxNumberOfSeats"));
int seatsAlreadyOccupied = Integer.parseInt(req.queryParams("seatsAlreadyOccupied"));
tripService.createTrip(tripOwner, startDate, startingPlace, tripDestination, tripPrice, maxNumberOfSeats,
seatsAlreadyOccupied);
res.status(201);
return null;
} , json());
At the end I obtain error 400 bad request. It is strange for me that when I want to see output on the console
System.out.println(req.queryParams());
I get json array of objects with values written by me on the website. However, when I want to see such output
System.out.println(req.queryParams("tripOwner"));
I get null. Does anyone have idea what is wrong here?
I think the main problem is that you are sending data to your Spark webservice with the 'Content-Type' : 'application/x-www-form-urlencoded' header. Try sending it as 'Content-Type' : 'application/json' instead, then in your Java code declare a String to receive req.body(), you'll see all your data in there.
Note: When you try to acces your data like this req.queryParams("tripOwner"); you're not accessing post data, but you're seeking for a get parameter called tripOwner, one that could be sent like this http://localhost:8080/trips/add?tripOwner=MyValue.
I would advise using postman to post a request to your server and see if it works. Try a different content type too. Try using curl and play with the various headers you are sending. 400 suggests the wrong data is being sent or expected data is missing or the data is the wrong type but based on your code you've provided I can see nothing wrong (but see below).
When your server receives a request log all request headers being received and see what changing them does. If it works in postman then you can change your client code to mirror the headers postman is using.
Does your spark server validate the data being sent before your controller code is hit? If so ensure you are adhering to all validation rules
Also on looking at your code again your client is sending the data in the post data but your server is expecting the data in the query string and not in the post data?
What happens if your server just sends a 201 response and does nothing else? Does your client get a 201 back? If so it suggests the hook up is working but there is something wrong with the code before you return a 201, build it up slowly to fix this.
Ok, I managed to cope with that using another approach. I used Jackson and ObjectMapper according to Spark documentantion. Thanks for your answers.
You can see more about that here: https://sparktutorials.github.io/2015/04/03/spark-lombok-jackson-reduce-boilerplate.html
You're probably just needed to enable CORS(Cross-origin resource sharing) in your Spark Server, which would have allowed you to access the REST resources outside the original domain of the request.
Spark.options("/*", (request,response)->{
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
if (accessControlRequestHeaders != null) {
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
}
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
if(accessControlRequestMethod != null){
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
}
return "OK";
});
Spark.before((request,response)->{
response.header("Access-Control-Allow-Origin", "*");
});
Read more about pre-flighted requests here.
I have been struggling with this for quite a while now, and other than decided that I hate CORS with a passion, I can also confirm that the internet is full of ideas, but very few working solutions to this problem so thought I would try to get the answer once and for all.
The objective is to write angular code that can do the following.
1. Set the headers to allow for CORS.
2. Log into a CORS enabled application (in this case media wiki)
3. Make an api call to receive some JSON data.
I will even set up a test mediawiki server (with semantic media wiki) and set up a test user just for this. And who knows, if people are interested enough I'll even attempt to use the answer to write the worlds simplest CORS module for Angular.
On the server I'll do three things.
Install mediawiki and semantic Media wiki
Change the settings (in LocalSettings.php)
$wgEnableAPI = true;
$wgCrossSiteAJAXdomains = array( 'http://127.0.0.1:30004' );
$wgAPIRequestLog = "$IP/log/wgAPIRequestLog.log";
And change .htaccess to set the headers.
# CORS Headers (add this)
<ifModule mod_headers.c>
Header always set Access-Control-Allow-Origin: "*"
Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "X-Requested-With, content-type"
</ifModule>
# BEGIN WordPress (you should have this in your original WP .htaccess)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# CORS OPTIONS (add this too)
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
I think this is all I need to do, however, as I have only been able to make CORS requests in angular after using a chome extension to turn of origin headers, I don't know if this will work.
In the meanwhile, if anyone has any ideas or good resources for this. Please post.
====================== And now set up =====================
So have now set up a mediawiki for this purpose
Mediawiki url 'http://v-ghost.port0.org:8081/apiwiki'
User 'whowillhelp'
Password 'InternetWill'
If you want to try an API call:
http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=jsonfm
If you haven't logged in, it will return:
{
"error": {
"code": "readapidenied",
"info": "You need read permission to use this module",
"*": "See http://v-ghost.port0.org:8081/apiwiki/api.php for API usage"
}
}
Thats all OK.
If you run the same http.get('http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=json' in angular you will get a
XMLHttpRequest cannot load http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[MsgType::1]][[Parent::Support%20Functions]]|%3FMenuName&format=jsonfm. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:30004' is therefore not allowed access.
That's wrong on many levels:
first, it is horribly insecure to enable CORS without limitations on any service that is even remotely public.
second, you need to set the Access-Control-Allow-Credentials header for anything that CORS is actually useful for (if it's a public API, just use JSONP). MediaWiki does this for you, when properly configured.
third, $wgCrossSiteAJAXdomains takes domain names as its arguments, not URL prefixes, so that should be $wgCrossSiteAJAXdomains = array( '127.0.0.1:30004' );.
fourth, you need to set the origin parameter in the example, ie. the correct URL is 'http://v-ghost.port0.org:8081/apiwiki/api.php?action=ask&query=[[Msgtype::1]]|%3FMenuName&format=json&origin=http://127.0.0.1:30004.
Thank you Quentin.
After an awful lot of faffing about, it turns out that CORS is fully controlled bt the server, and at that the web server not the application.
All that was needed (once the API was on) would have been to add the stuff to the .htaccess file. Configure Apache to read it (http.conf).
You also need to ensure that mod_headers (called headers_module when httpd -t -D DUMP_MODULES) is loaded, but it should be default with Apache 2).
And if in doubt, there is a test service:)
http://client.cors-api.appspot.com/
================= Seems to work now ===================
And as I try to be a nice person that give back. Here is the factory I wrote. Technically it requires three calls (if login is required) one if you just want to run queries. Hope it helps someone
Might we worth mentioning, Mediawiki (and potentially all CORS implementations) require you to log in twice, once for authentication, once with the token it sent earlier. Guessing this is related to building the cookie.
.factory('CORSconnectFactory', function($http, $q){
//To call any of the http calls just do
// CORSconnectFactory.login(options )
// .then(function(data)
var CORSconnectFactory = {};
var CORScredentials = {};
var urlInit;
var deferred = $q.defer();
var datareq = {
method: 'POST',
//url: 'http://v-ghost.port0.org:8081/dbfswiki/api.php?action=login&format=json',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' //Set the coding, otherwise the server can't read you're request
}
//withCredentials: true,
/*
If you set Credentials your server gets rather picky oc CORS, more specifically Header always set Access-Control-Allow-Origin: needs to be set to exact address.
*/
//data: "lgname=APIread&lgpassword=apiread01"
}
CORSconnectFactory.initSettings = function(url, withCredentials) {
urlInit = url;
datareq.withCredentials= withCredentials;
}
CORSconnectFactory.login = function(id, password){
datareq.url = urlInit + "?action=login&format=json";
datareq.data= "lgname=" + id + "&lgpassword=" + password;
return $http(datareq)//You don't have to return this request, but it helps as it lets you use .login's promise in your code
.success(function(data) {
var results = data.login; //You might have to work around to find the right part of the structure
if ( results.result === "NoName"){
console.log("New request for Token")
} else if ( results.result === "NeedToken" ) {
console.log("Need a token this time") //Mediawiki API requires login then login with token to accept the connection.
CORScredentials = data.login
return results.result;
}
});
}
CORSconnectFactory.tokenReq = function(){
datareq.data = datareq.data = datareq.data + "&lgtoken=" + CORScredentials.token;
return $http(datareq)
.success(function (data) {
results= data.login;
CORScredentials=data.login;
console.log("And I am now " + results.result);
})
}
CORSconnectFactory.query = function(queryString) {
datareq.url = urlInit + "?action=ask&query="+ queryString + "&format=json";
datareq.data = ""; //Don't send data, it confuses the poor query (and your login details is in the token
return $http(datareq)
.success(function(data) {
var results = data.query.results;
return results;
});
}
return CORSconnectFactory;
});
I am having trouble with Restangular 1.4 sending authorization headers to an external web api, which challenges if no such header is provided.
In the following code I try to set the default headers to include basic auth header, but when I look at Fiddler it tells me that no authorization header is present from the start, so the api call is rejected as unauthorized.
Does anyone know if this a bug in Restangular, or whether there is something lacking in the way I have tried to code the auth header?
angular.module('MyAPIService', ['restangular']).factory('MyAPIService', function (Restangular) {
Restangular.setBaseUrl('http://mywebapi/api/');
var encoded = Base64.encode(username + ":" + password);
Restangular.setDefaultHeaders({ Authorization: 'Basic ' + encoded });
return Restangular.one('users', username).get();
Try to set headers in configuration block (not sure about factories). My code looks like this:
angular.module('app', ['restangular'])
.config(['RestangularProvider', function (RestangularProvider) {
// ... some code here
RestangularProvider.setDefaultHeaders({
token: 'some-secret-token'
// other headers
});
// ... some code here
}]);
and works for me.
Turns out that the issue is that the Authorization header is null for all preflight (i.e.) OPTIONS request. (to learn about them, see the section on Preflighted Requests at [https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS). So since I was able to control the API's Basic Auth handling, I made the API not issue a 401 challenge for such preflight requests. The Authorization header was present on non-preflight requests (GET,POST,PUT,DELETE).