0
votes

In the CakePHP 3 Blog Tutorial, users are conditionally authorized to use actions like edit and delete based on ownership with the following code:

public function isAuthorized($user)
{
    // All registered users can add articles
    if ($this->request->getParam('action') === 'add') {
        return true;
    }

    // The owner of an article can edit and delete it
    if (in_array($this->request->getParam('action'), ['edit', 'delete'])) {
        $articleId = (int)$this->request->getParam('pass.0');
        if ($this->Articles->isOwnedBy($articleId, $user['id'])) {
            return true;
        }
    }

    return parent::isAuthorized($user);
}

public function isOwnedBy($articleId, $userId)
{
    return $this->exists(['id' => $articleId, 'user_id' => $userId]);
}

I've been attempting to implement something similar for my own tables. For example, I have a Payments table, which is linked to Users through several different tables as follows:

  • Users->Customers->Bookings->Payments.

Foreign keys for each:

  • user_id in Customers table = Users->id (User hasOne Customer)
  • customer_id in Bookings table = Customers->id (Customer hasMany Bookings)
  • booking_id in Payments table = Bookings->id(Booking hasMany Payments)

My AppController's initialize function:

public function initialize()
    {
        parent::initialize();

        $this->loadComponent('RequestHandler');
        $this->loadComponent('Flash');
        $this->loadComponent('Auth',[
            'authorize' => 'Controller',
        ]);

        $this->Auth->allow(['display']); //primarily for PagesController, all other actions across the various controllers deny access by default
    }

In my PaymentsController, I have the following

public function initialize()
    {
        parent::initialize(); 
    }

public function isAuthorized($user)
    {        
        if (in_array($this->request->action,['view', 'edit', 'index', 'add']
            return (bool)($user['role_id'] === 1); //admin functions
        }

        if (in_array($this->request->action,['cart'])) {
            return (bool)($user['role_id'] === 2) //customer function
        }

        if (in_array($this->request->action, ['cart'])) {
            $bookingId = (int)$this->request->getParam('pass.0');
            if ($this->Payments->isOwnedBy($bookingId, $user['id'])) {
                return true;
            }
        }

        return parent::isAuthorized($user);
    }

    public function isOwnedBy($bookingId, $userId)
    {
        return $this->exists(['id' => $bookingId, 'user_id' => $userId]);
    }

I'm unsure as to how to link through the different tables to determine ownership.

  • Currently if a customer who is paying for Booking #123 could just change the URL so they are paying for Booking #111, provided that Booking exists in the database.
  • Additionally, the Booking ID is passed to the Cart function (since customers are paying for a specific booking). For example: If customer is paying for Booking #123, then the URL = localhost/project/payments/cart/123. Upon submitting their cart, a new Payment entry is created.

Also, regarding the getParam and isOwnedBy methods, hovering over them in my editor shows this:

  • Method 'getParam' not found in \Cake\Network\Request
  • Method 'isOwnedBy' not found in App\Model\Table\PaymentsTable

However, I've gone through the entire BlogTutorial and can't find anywhere else that getParam or isOwnedBy is used or set up in the Model.

1
In your PaymentsController::isAuthorized(), how could the 3rd condition if (in_array($this->request->action, ['cart'])) { be met, when the 2nd (same) condition were true ?code-kobold
Ah yeah forgot about that. I removed it. I'm now getting Method getParam does not exist as a Cake error when trying to access cart pages, regardless of ownership.mistaq
Fixed, will post answer shortly.mistaq

1 Answers

0
votes

In the IsAuthorized function in PaymentsController:

if (in_array($this->request->action, ['cart'])) {
    $id = $this->request->getParam('pass'); //use $this->request->param('pass') for CakePHP 3.3.x and below.
    $booking = $this->Payments->Bookings->get($id,[
        'contain' => ['Artists']
    ]);
    if ($booking->artist->user_id == $user['id']) {
        return true;
    }
}