How throw forbidden exception from middleware in laravel5? - php

I am writing a middleware in laravel 5. I want to throw a forbidden exception with code 403 from middleware. My middleware function is given below:
use Exception;
public function handle($request, Closure $next)
{
if (!Auth::check()) {
throw new Exception("Access denied", 403);
}
return $next($request);
}
I am calling my middleware from controller and I am getting error message with code 500 but not 403. How can I resolve this?

You can simply use the abort() helper. (Or App::abort())
public function handle($request, Closure $next) {
if (!Auth::check()) {
abort(403, 'Access denied');
}
return $next($request);
}
You can handle these exceptions inside App\Exceptions\Handler by overriding render() For example:
public function render($request, Exception $e)
{
if($e instanceof HttpException && $e->getStatusCode() == 403){
return new JsonResponse($e->getMessage(), 403);
}
return parent::render($request, $e);
}

Related

Laravel custom error taking too long to response

Laravel Framework 8.48.0
PHP 7.4.18
Local Environment: Xampp, Windows10
I am developing RESTful API using Laravel 8. I have written some logic inside the register() method to make the error response better and more straightforward. Everything is working perfectly. But the problem is when Laravel detects an exception that doesn't fall any of this logic and APP_DEBUG=true, this piece of code start executing and takes too long to respond; it says execution timeout. If I clean the register() method, it shows an exception within 1 or 2 secs. What's wrong with my code?
I want a better and more precise error response + when APP_DEBUG=true quickly shows an error exception.
I think this is the culprit.
if (env('APP_DEBUG', false)) {
return parent::render($request, $exception);
}
Handler.php
class Handler extends ExceptionHandler
{
use ApiResponser;
protected $dontReport = [
//
];
protected $dontFlash = [
'password',
'password_confirmation',
];
public function register()
{
$this->renderable(function (Exception $exception, $request) {
if ($request->wantsJson()) {
if ($exception instanceof HttpException) {
$code = $exception->getStatusCode();
$message = Response::$statusTexts[$code];
return $this->errorResponse($message, $code);
}
if ($exception instanceof AuthenticationException) {
return $this->errorResponse($exception->getMessage(), Response::HTTP_UNAUTHORIZED);
}
if ($exception instanceof AuthorizationException) {
dd('authorization exception');
return $this->errorResponse($exception->getMessage(), Response::HTTP_FORBIDDEN);
}
if ($exception instanceof ValidationException) {
$errors = $exception->validator->errors()->getMessages();
return $this->errorResponse($errors, Response::HTTP_UNPROCESSABLE_ENTITY);
}
if (env('APP_DEBUG', false)) {
return parent::render($request, $exception);
}
return $this->errorResponse('Unexpected error occurred. Please contact your administrator for help.', Response::HTTP_INTERNAL_SERVER_ERROR);
}
});
}
}

Show the index blade on 404 in laravel

I would like to show the index page if the route is not found.
I have modified the App\Exceptions\Handler like so and that did not work
public function render($request, Exception $exception)
{
if ($this->isHttpException($exception) || $exception instanceof UnauthorizedException) {
if ($exception->getStatusCode() == 404) {
return view('app.index');
}
}
return parent::render($request, $exception);
}
it's my mistake I can accomplish the same thing by rooting all requests to the index.
Route::get('/{any}', 'FrontEndController#index')->where('any', '.*');

Capture Request state at the time of an exception

I have a Slim Framework application with a custom errorHandler, and a small middleware stack. My middleware adds attributes to the Request object which I would like to have access to from my error handler in the event of an exception. For example:
$app->get('/endpoint', function($request $response, $args) {
$myAttribute = $request->getAttribute('myAttribute'); //returns 'myValue'
throw new \Exception(); //any code that throws an error
})->add(function($request, $response, $next) {
$request = $request->withAttribute('myAttribute', 'myValue');
$response = $next($request, $response);
return $response;
});
$app->getContainer['errorHandler'] = function($c) {
return function($request, $response, $exception) {
$myAttribute = $request->getAttribute('myAttribute'); //returns null
return $response;
}
};
The attribute does not exist within the Request object inside the error handler because the cloned Request from inside the route has not been returned after traversing through the middleware stack. Is it possible to access the Request and Response objects as they exist, at the time (in the location) the exception is thrown? I can't explicitly pass them (for example, SlimException) because I'm trying to handle unexpected errors as well.
I've created two, somewhat hacky, solutions to capturing Request and Response state when exceptions are thrown. Both attempt to insert a try/catch as close to the center of the middleware stack as possible (without repeating code), and involve wrapping the original exception in a new exception class together with the modified endpoint parameters.
Middleware
This works as long as attention is paid to the order that middleware is added. Unfortunately it does require the innermost middleware is added to each route, or at the very least, "before" the middleware modifying the Request and/or Response objects. This won't catch any changes to Request/Response made inside, nor after the route.
class WrappedException extends \Exception {
public $exception;
public $request;
public $response;
public function __construct($exception, $request, $response) {
$this->exception = $exception;
$this->request = $request;
$this->response = $response;
}
}
$app->get('/endpoint', function($request $response, $args) {
throw new \Exception(); //any code that throws an error
})->add(function($request, $response, $next) {
try {
$response = $next($request, $response);
} catch (\Exception $exception) {
throw new WrappedException($exception, $request, $response);
}
return $response;
});
$app->add(function($request, $response, $next) {
$request = $request->withAttribute('myAttribute', 'myValue');
$response = $next($request, $response);
return $response;
});
$app->getContainer['errorHandler'] = function($c) {
return function($request, $response, $exception) {
if ($exception instanceof WrappedException) {
//returns 'myValue'
$myAttribute = $exception->request->getAttribute('myAttribute');
}
return $response;
}
};
Route Class
This wraps all routes in a try block, and makes for a bit cleaner route code, but you must be sure to extend all routes from the RouteBase class.
class WrappedException extends \Exception {
public $exception;
public $request;
public $response;
public function __construct($exception, $request = null, $response = null) {
$this->exception = $exception;
$this->request = $request;
$this->response = $response;
}
}
class RouteBase {
public function __call($method, $arguments) {
if (method_exists($this, $method)) {
try {
$this::$method(...$arguments);
} catch (\Exception $e) {
throw new WrappedException($e, ...$arguments);
}
} else {
throw new \Exception('Route method not found.');
}
}
}
class RouteClass extends RouteBase {
//PROTECTED -- must be callable by parent class, but not outside class
protected function get(Request $request, Response $response, $args) {
throw new \Exception('A new exception!');
$response->write('hey');
return $response;
}
}
$app->get('/endpoint', 'RouteClass:get');
$app->add(function($request, $response, $next) {
$request = $request->withAttribute('myAttribute', 'myValue');
$response = $next($request, $response);
return $response;
});
$app->getContainer['errorHandler'] = function($c) {
return function($request, $response, $exception) {
if ($exception instanceof WrappedException) {
//returns 'myValue'
$myAttribute = $exception->request->getAttribute('myAttribute');
}
return $response;
}
};
Upgrade to Slim 4 (if you can)
Worth noting now that Slim 4 fixes this issue. Personally, it was kind of a pain to upgrade as a lot changed, especially with the Dependency Injection containers (I went from Slim v3.12 => 4.8).
In Slim 4 they moved both the routing and the error handling into (separate) middlewares.

Laravel 5.5 $exception instanceof AuthenticationException not working as expected

guys. I am new to Laravel. Just installed 5.5 and try to catch the AuthenticationException in App\Exceptions\Handler like below
public function render($request, Exception $exception)
{
if ($exception instanceof AuthenticationException) {
//Do something
}
}
The problem is ($exception instanceof AuthenticationException) always return false.
dd($exception instanceof AuthenticationException) //return false.
When I dd($exception) I got
AuthenticationException{
#gurad...
....
.....
}
Then I try
get_class($exception) return \Illuminate\Auth\AuthenticationException
However,
dd($exception instanceof Exception) //return true.
Please help. Thanks.
You should make sure you use class from valid namespace:
public function render($request, Exception $exception)
{
if ($exception instanceof \Illuminate\Auth\AuthenticationException) {
//Do something
}
return parent::render($request, $exception);
}
You mentioned:
dd($exception instanceof Exception) //return true.
That's true. Each exception class that will extend Exception class will return true for this, that's why in your handler you should make sure you first verify specific classes and not exception class, for example if you used:
public function render($request, Exception $exception)
{
if ($exception instanceof Exception) {
//Do something 1
}
if ($exception instanceof \Illuminate\Auth\AuthenticationException) {
//Do something 2
}
return parent::render($request, $exception);
}
always //Do something 1 would be launched first.

How to return custom API response for "No query results for model", Laravel

I am building an RESTful API in Laravel 5.2.
In my resource controllers I want to use implicit model binding to show resources. e.g.
public function show(User $users)
{
return $this->respond($this->userTransformer->transform($users));
}
When a request is made for a resource that doesn't exist Laravel automatically returns the NotFoundHttpException
NotFoundHttpException
I want to return my own custom response but how can I do that for a query that is done using route model binding?
Would something like this Dingo API response answer be able to be implemented?
Or will I stick with my old code which was something like this:
public function show($id)
{
$user = User::find($id);
if ( ! $user ) {
return $this->respondNotFound('User does not exist');
}
return $this->respond($this->userTransformer->transform($users));
}
So I could see if a resource (user) was not found and return an appropriate response.
See if you can catch ModelNotFound instead.
public function render($request, Exception $e)
{
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
dd('model not found');
}
return parent::render($request, $e);
}
I think a good place would be in the Handler.php file under /app/Exceptions
public function render($request, Exception $e)
{
if ($e instanceof NotFoundHttpException) {
// return your custom response
}
return parent::render($request, $e);
}
In Laravel 7 and 8 you can do something like this.
In app/Exception/Handler.php class, add the render() method like below(if it doesn't exist).
Note that instead of type hinting Exception class you should use Throwable .
use Throwable;
public function render($request, Throwable $e)
{
if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) {
//For API (json)
if (request()->wantsJson()) {
return response()->json([
'message' => 'Record Not Found !!!'
], 404);
}
//Normal
return view('PATH TO YOUR ERROR PAGE');
}
return parent::render($request, $e);
}

Categories