Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.1] Custom Error Messages for Unauthorized Access #16601

Closed
wants to merge 1 commit into from

Conversation

atefth
Copy link

@atefth atefth commented Nov 30, 2016

Summary:

After creating a Policy Class for the Current User and a related Eloquent Model, we need to register it with the Gate Class to essentially manage the various (CRUD) operations that the User can perform on that Model.

The authorize function implemented in the Gate Class takes in 2 arguments - $ability [string] indicates what operation the User wants to perform on the Model; while $arguments [string or Illuminate\Support\Collection] indicates what error message is to be returned, if the User is not permitted to perform the operation.

The method in turn calls the allow and deny methods implemented in the HandlesAuthorization trait: returning null (access granted) or raising an AuthorizationException (access denied). The exception is constructed with the default message - "This action is unauthorized.", unless $arguments was provided to override it.

The deny method accepts a $message parameter which is initialized to the default error message. However, the $arguments to override the default was not being passed down from the authorize function as a parameter, while calling the deny function. Thus, the default error message could not be changed.

Here is the issue.

Solution:

Just calling the deny method with the given $arguments, from the controller, as parameters solves this problem:

public function authorize($ability, $arguments = []) {
    $result = $this->raw($ability, $arguments);
    if ($result instanceof Response) {
        return $result;
    }
    // return $result ? $this->allow() : $this->deny();
    return $result ? $this->allow() : $this->deny($arguments);
}

@GrahamCampbell GrahamCampbell changed the title Custom Error Messages for Unauthorized Access [5.1] Custom Error Messages for Unauthorized Access Nov 30, 2016
@taylorotwell
Copy link
Member

No plans to implement this currently.

@mtpultz
Copy link

mtpultz commented Nov 30, 2016

@taylorotwell is there anyway to customize a failed policy message for an AuthorizationException? This pull request is related to a stack overflow question I posted yesterday where I'm looking for a way to get something equivalent to a validation error bag, but for a failed policies regardless of the policy API used - controller, or via the User model. This is something that I find I come into contact with regularly, and instead of applying what feels like a "clean" solution I'm currently just abort(403, trans($key)); within the policy.

@d-damien
Copy link

d-damien commented May 22, 2019

Good APIs and exceptions systems allow to customize error messages. I'm writing the permissions part of a software and as of now, I feel sort of trapped by all the responses I have to write to handle every case :

if (Gate::denies($permission_1, $var1))
  return new JsonResponse(['error' => $errorMsg, 403);

if (Gate::denies($permission_2))
  return new JsonResponse(['error' => '...'], 403);
// etc.

Of course I could write my own class, but having it by default would seem appropriate.
I feel we should be able to write one-liners one-liners like :

$this->authorize('permission_1', $var1, $errorMsg);
$this->authorize('permission_2', '...');

Just before the $request->validate(), it would make it (even more) clear and beautiful.

@d-damien
Copy link

d-damien commented May 23, 2019

Bypass for anyone interested :

Controller.php :

// override the authorize method
class Controller extends BaseController {
  use AuthorizesRequests {
    authorize as traitAuthorize;
  }
  // ...
  public function authorize($ability, $related, $errorMsg) {
    if (Gate::denies($ability, $related))
      throw new AuthorizationException($errorMsg);
    return true;
   }
}

Exception/Handler.php :

public function render($request, $exception) {
  if ($exception instanceof AuthorizationException)
    // or however you want it handled
    return new JsonResponse(['error' => $exception->getMessage()], 403);
  parent::render($request, $exception);
}

You can now define your favorite Gates in AuthServiceProvider, and call $this->authorize() in your controllers instead of conditional verifications : the system will check permission and automatically render a proper 403 with custom message in case of failure.

$this->authorize('customGate', $relatedObjectToCheckPermissionAgainst, $errorMsg);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants