3

I have added the Saptie Laravel Permission Package in a Laravel 5.8 API application. Every works fine and I get exception when a non admin user tries to access admin specific routes.

However the default exception is rendered as HTML 403 User does not have the right roles. Considering I am using this inside an API application, I would like to return my own custom message for such exceptions.

I tried checking if the auth()->user()->hasRole('admin') but still got the same default exception page. Here's my code

route

Route::post('products', 'ProductController@store')->middleware('role:super-admin|admin'); // create a new product

Controller method

if (auth()->user()->hasRole('admin')) {

    // create & store the product
    $product = Product::create($request->all())

    // return new product
    $responseMessage    = 'Successful operation';
    $responseStatus     = 200;
    $productResource    = new ProductResource($product);

    return response()->json([
        'responseMessage'   => $responseMessage,
        'responseStatus'    => $responseStatus,
        'product'           => $productResource
    ]);
} else {

    return response()->json([
        'responseMessage'   => 'You do not have required authorization.',
        'responseStatus'    => 403,
    ]);
}

Why is my custom message not showing?

apokryfos
  • 38,771
  • 9
  • 70
  • 114
Mena
  • 1,873
  • 6
  • 37
  • 77
  • 1
    The code you posted does not throw a `UnauthorizedException`, did you protect your routes through the middleware e.g. `role:admin`? If yes then your controller is never reached so your code is never run. – Remul Sep 03 '19 at 11:27
  • @Remul yes I am calling the `role:admin` middleware on the route. See edited post for the route. If the user role is being checked before the controller is hit, then what do I do to return json response instead of rendering html 403 page? – Mena Sep 03 '19 at 11:33

1 Answers1

8

Because you are protecting your routes through the role middleware the UnauthorizedException will be thrown before your controller code is ever reached.

What you can do is use laravels exception handler render method and check the exception type and return your own response:

from the docs:

The render method is responsible for converting a given exception into an HTTP response that should be sent back to the browser. By default, the exception is passed to the base class which generates a response for you. However, you are free to check the exception type or return your own custom response

app/Exceptions/Handler.php

use Spatie\Permission\Exceptions\UnauthorizedException;

public function render($request, Exception $exception)
{
    if ($exception instanceof UnauthorizedException) {
        return response()->json([
            'responseMessage' => 'You do not have required authorization.',
            'responseStatus'  => 403,
        ]);
    }

    return parent::render($request, $exception);
}
Remul
  • 7,874
  • 1
  • 13
  • 30
  • I added your code to the `render` method of *app/Exceptions/Handler.php* but still got the default exception page. – Mena Sep 03 '19 at 11:45
  • Did you import `UnauthorizedException`? e.g. `use Spatie\Permission\Exceptions\UnauthorizedException;` – Remul Sep 03 '19 at 11:46
  • This has now been added to the [documentation](https://docs.spatie.be/laravel-permission/v3/advanced-usage/exceptions/), thanks guys! – Laurence Cooper Oct 07 '19 at 10:40