How to use middleware and controller on one route - laravel

I have to add CORS policy to my request.
So I created middleware
I already tried the following :
Route::get('/test', ['middleware' => 'cors', 'cvGenerator#show'])
or
Route::get('/test', 'cvGenerator#show');
//inside controller
$this->middleware('cors');
but none of the above work. CORS policy still aborted
my middleware code:
namespace App\Http\Middleware;
use Closure;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin' , '*')
->header('Access-Control-Allow-Methods' , 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers' , 'X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding');
}
}
And Controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use PDF;
use Illuminate\Support\Facades\Storage;
class cvGenerator extends Controller
{
public function show(Request $request)
{
$this->middleware('cors');
echo 'test';
//some code that generate output
}
}
How can I pass the request?

If you have just one route that should go through the middleware. Also middleware doesn’t belong in the controller.
Route::get('/test', 'cvGenerator#show')->middleware('cors');
If you have more than one route, you can use a route group.
Route::group(['middleware' => ['cors']], function () {
Route::get('/test', 'cvGenerator#show');
});
Also Laravel has a pretty good docs about middleware.
CORS
We're using this middleware to support pre-flight CORS requests:
<?php
namespace App\Http\Middleware;
use Closure;
class AddCorsHeaders
{
/**
* Check for CORS request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
*
* #return mixed
*/
public function handle($request, Closure $next)
{
$headers = [
'Access-Control-Allow-Origin' => $request->header('Origin'),
'Access-Control-Allow-Methods' => 'HEAD, POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Headers' => $request->header('Access-Control-Request-Headers'),
];
if ($request->isMethod('OPTIONS')) {
return response()->json('{"method":"OPTIONS"}', 200, $headers);
}
if ($request->header('Origin')) {
config(['access-control-origin' => $request->header('Origin')]);
}
return $next($request);
}
}
Don't forget to add this to your kernel.php in the $routeMiddleware array.
'cors' => \App\Http\Middleware\AddCorsHeaders::class,

Related

Uncaught Error: Call to a member function send() on null In laravel application

In my laravel app the api stopped to work and the terminal warn me error:PHP Fatal error: Uncaught Error: Call to a member function send() on null.
I'm using custom middleware
jwtMiddleware:
<?php
namespace App\Http\Middleware;
use App\Utils\CustomResponse;
use Closure;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Lang;
use Symfony\Component\HttpFoundation\Response;
use Tymon\JWTAuth\Facades\JWTAuth;
class jwtMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
try {
$user = JWTAuth::parseToken()->authenticate();
} catch (Exception $e) {
if($e instanceof \Tymon\JWTAuth\Exceptions\TokenInvalidException){
return CustomResponse::setFailResponse(Lang::get('error.token.invalid'), Response::HTTP_NOT_ACCEPTABLE);
}else if($e instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException){
return CustomResponse::setFailResponse('error.token.expired', Response::HTTP_NOT_ACCEPTABLE);
}else{
return CustomResponse::setFailResponse('error.token.not found', Response::HTTP_UNAUTHORIZED);
}
}
return $next($request);
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Lang;
use app\ENum\LangEnum;
class setLocale
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$locale = substr($request->server('HTTP_ACCEPT_LANGUAGE'),0,2);
if($locale == LangEnum::IT){
$locale = LangEnum::IT;
}else{
$locale = LangEnum::EN;
}
App::setLocale($locale);
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers',' Origin, Content-Type, Accept, Authorization, X-Request-With')
->header('Access-Control-Allow-Credentials',' true');
}
}
Vue console panel (I have a frontend linked made with nuxt) said:
Access to XMLHttpRequest at 'http://localhost:8000/api/products' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

Laravel VerifyCsrfToken exclude not working

I'm having an issue excluding /api route from verifying token.
I'm trying to exclude all routes but not working
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
//
'*',
];
}
What I suggest is, create a middleware and use it in your routes:
Create app/Http/Middleware/Cors.php
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, \Closure $next)
{
$response = $next($request);
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization');
return $response;
}
}
Modify app/Http/Kernel.php
protected $routeMiddleware = [
...
'cors' => \App\Http\Middleware\Cors::class,
];
Finally, use it in your route file eg: routes/web.php
Route::middleware(['cors'])->group(function () {
Route::get('/', 'YourController#yourFunction');
});

Return every request as plain json Laravel using Middleware

I have a route in my web.php that returns a view:
Route::get('/', function () {
return view('welcome');
});
welcome is default Laravel view welcome.blade.php.
I have Middleware called AlwaysReturnJson and it contains:
<?php
namespace App\Http\Middleware;
use Closure;
class AlwaysReturnJson
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
}
I set up this middleware in Kernel.php as global middleware:
protected $middleware = [
\App\Http\Middleware\AlwaysReturnJson::class
];
What I expect is to get plain text/json of welcome file in my browser when I navigate to given route but I always get it as html and it render page properly. I checked it, it applies middleware on every request so that is not a problem. Why is this happening and shouldn't it convert that view to a plain text? Am I doing something wrong?
If you want to set a header for your response you can do this:
namespace App\Http\Middleware;
use Closure;
class AlwaysReturnJson
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
If you want to force return valid json content use this middleware instead:
namespace App\Http\Middleware;
use Closure;
class AlwaysReturnJson
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
return response()->json($response->getContent());
}
}
See Laravel docs about after middleware for more info.
You can alternatively return json response on your controller without any middleware needed:
Route::get('/', function () {
return response()->json(
view('welcome')->render()
);
});
You may want to use laravel After middleware (the middleware would perform its task after the request is handled by the application) and then set the content-type of response.
<?php
namespace App\Http\Middleware;
use Closure;
class AfterAlwaysReturnJson
{
public function handle($request, Closure $next)
{
$response = $next($request);
return $response->header('Content-Type', 'application/json');
}
}

Laravel API CORS mode not working

I did a lot of research and I implemented the following middleware to get around the CORS error I keep getting...
Middleware/Cors.php
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS')
->header('Access-Control-Allow-Headers', 'content-type');
}
}
?>
Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'cors' => App\Http\Middleware\Cors,
];
Routes.php
Route::post('/content', array('middleware' => 'cors', 'uses' => 'Test#save'));
This seems to be configured properly. But when I make the request using fetch API...
fetch('http://laravel.dev/content', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin':'*'
},
body: JSON.stringify({
})
})
//.then((response) => response.json())
.then((response) => response.text())
.then((text) => {
console.log(text);
});
I still get this error...
Fetch API cannot load http://laravel.dev/content.
Response to preflight request doesn't pass access
control check: No 'Access-Control-Allow-Origin' header
is present on the requested resource.
I tried adding no-cors mode to my fetch response, and it worked, I got an opaque response, but I need cors mode to get a proper request.
It might be worthwhile to note that my App and my Laravel restAPI are located in the same htdocs folder on XAMPP. I'm not sure if this is an issue.
I also tried adding the headers at the top of my Routers.php file but I still get the same error. Can I even configure a restAPI using laravel?
Try to remove
->header('Access-Control-Allow-Headers', 'content-type');
in class Cors like this
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');
}
}
?>
It worked for me.I hope it helpfull for you

Laravel 5 CORS middleware not working for group of routes

I am appling cors middleware to access json from some other domain.
This code works just fine :-
Route::get('api/authenticate', ['middleware' => 'cors', function() {
return Response::json(array('name' => 'Steve Jobs', 'state' => 'California'));
}]);
But when I apply it to :-
Route::group(['prefix' => 'api', 'middleware' => 'cors'], function()
{
Route::resource('authenticate', 'AuthenticateController', ['only' => ['index']]);
Route::post('authenticate', 'AuthenticateController#authenticate');
});
it gives me error in console,
No 'Access-Control-Allow-Origin' header is present on the requested resource
I have a have added Cors middleware, cors.php :-
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
return $next($request)->header('Access-Control-Allow-Origin', '*')->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
}
}
Please help. Thanks.
I tried to find solution for mine as well when sending JWT into header. This is what resolved my case:
1) Add the cors in route middleware
protected $routeMiddleware = [
...
'cors' => \App\Http\Middleware\Cors::class,
];
2) Add the cors in global middlewre
protected $middleware = [
...
\App\Http\Middleware\Cors::class,
];
3) Add custom Access-Control-Allow-Headers in Cors middleware app/Http/Middleware/Cors.php
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Log;
class Cors {
public function handle($request, Closure $next) {
Log::info("Using cors for " . $request->url());
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Accept, Authorization, X-Request-With');// <-- Adding this
}
}

Resources