minaremonshaker's avatar

Authorization Exception Not Triggered When Admin Has No Tickets

In the controller method below, I'm experiencing an authorization issue. When an admin has no tickets, I receive an empty array [] instead of an authorization exception. However, when tickets exist for the admin, I correctly get the unauthorized exception. The expected behavior is that I should receive an authorization exception whenever I try to access admin tickets, regardless of whether tickets exist or not.

NOTE: i have sloved this by creating a gate in the AppServiceProvider in the boot method as below but i don`t know if that is correct or not

      Gate::define('showUserTicketList', function (User $user ,User $author) {

           if($user->hasPermissionTo('ShowOwnTicket')) {
                return $user->id === $author->id;
           }

          return false;
      });
  • controller method :

     public function index(Request $request, User $author)
    {
    
        // $filters = $request->only(['per_page']);
    
        $tickets = TicketsService::findTicketsByUserId($author);
    
        foreach ($tickets as $ticket) {
            Gate::authorize('view', [Ticket::class, $ticket]);
        }
    
        return TicketResource::collection($tickets);
    
    }
    
  • Service method:

    public static function findTicketsByUserId(User $author)
    {
        return QueryBuilder::for(Ticket::class)
            ->whereUserId($author->id)
            ->paginate();
    }
    
  • Policy: (TicketPolicy)

          public function viewAny(User $user): bool
      {
          if ($user->hasPermissionTo('ShowTicket')) {
              return true;
          }
    
          return false;
      }
    
0 likes
5 replies
minaremonshaker's avatar

hi i am doing this because i am using spaite query builder in my service to for searching and feltering

martinbean's avatar

@minaremonshaker I’m struggling to understand what you’re trying to achieve here? Why would you want an authorisation exception for no results? No results != unauthorised, and vice versa.

If you’re trying to stop non-admins from trying to view someone else’s tickets, then you should just have a simple ownership check in a TicketPolicy class:

class TicketPolicy
{
    public function view(User $user, Ticket $ticket): bool
    {
        return $ticket->user()->is($user);
    }
}

Then you can call this policy method when trying to view a ticket:

class TicketController extends Controller
{
    public function show(Ticket $ticket)
    {
        // Check that user can view the requested ticket
        Gate::authorize('view', $ticket);

        // Return ticket response...
    }
}
minaremonshaker's avatar

Hi, I want to prevent non-admin users from accessing other users' tickets. Each logged-in user should only see their own tickets.

For example, when I make a request to http://localhost:8000/api/authors/1/tickets, the 1 parameter represents an admin user. If this isn't the currently logged-in user, I expect to receive an unauthorized exception.

However, the issue is:

  • If user with ID 1 has no tickets, I get an empty array instead of an unauthorized exception

  • If user with ID 1 has tickets, the authorization works correctly and I get the unauthorized exception

I hope that clarifies my question.

martinbean's avatar
Level 80

Hi, I want to prevent non-admin users from accessing other users' tickets. Each logged-in user should only see their own tickets.

Then do that? Stop trying to shoe-horn this into tickets authorisation. As you’re finding, you can’t then authorise if there aren’t any tickets to authorise against.

The user identifier is in the route, so create some middleware that restricts access to other users:

class RestrictAccessToOwnedResources
{
    public function __construct(
        #[RouteParameter('user')] protected User $user,
    ) {}

    public function handle(Request $request, Closure $next)
    {
        abort_unless($this->user->is($request->user()), 403);

        return $next($request);
    }
}

Middleware checks if the authenticated user is the user specified in the URL, and returns a 403 Forbidden response if not.

If admins should be able to see tickets of any user, then just add to the if statement:

- abort_unless($this->user->is($request->user()), 403);
+ abort_unless($this->user->is($request->user() || $request->user()->isAdmin()), 403);

Please or to participate in this conversation.