Redirect issue based on the source of origin

I have a controller called ProductsController:

class ProductsController extends AppController {
 public function checkProduct() {
  $this->checkViewer();
 }
 public function viewProduct() {$this->checkViewer();}
}

In the AppController:

class AppController extends Controller {
....some code
 public function checkViewer() {
  if($this->Auth->user('type') != 3) {
   return $this->redirect(['controller' => 'Pages', 'action' => 'unauthorized']);
  }
 }
}

Now, there are 2 links:

  1. From the layout pageā€™s header: This link goes to the viewProduct() action.
  2. From any other controllerā€™s actionā€™s html page: This link goes to the checkProduct().

So, whenever, viewProduct() is accessed, it redirects but when checkProduct() is accessed, it does not. Why ?

I checked the following things correctly:

  1. Made sure that Auth user type is not equal to 3.
  2. I even changed the if condition to ā€œ== 3ā€, to check whether anything missing, but it works fine.
  3. When, I donā€™t call the checkViewer() in the action, rather, I provide the redirect(), then and there, it works fine.

Your ProductsController methods will need to return the result of checkView() to work properly.

class ProductsController extends AppController {
   public function checkProduct() {
      return $this->checkViewer();
   }
   public function viewProduct() {
      return $this->checkViewer();
   }
}

I often stumble over this detail of using ā€˜redirectā€™ :slight_smile:

1 Like

Thank @dreamingmind, for your reply. Sorry, for one mistake i had made in the code.

The code actually is:

class AppController extends Controller {
....some code
 public function checkViewer() {
  if($this->Auth->user('type') != 3) {
   return $this->redirect(['controller' => 'Pages', 'action' => 'unauthorized']);
  }
  return true;
 }
}

This is like Iā€™m checking both in checkProduct() and viewProduct() that whether the user can access the particular action or not. If the user canā€™t access then, he will be redirected to unauthorized page else he will access the views related to the actions.

That is below the $this->checkViewer(), the queries are being fetched and then to the html page of the corresponding actions.

So, if I will write return before the checkViewer() like you mentioned in the post, then user can never access the corresponding views.

Please, if you can give any insight regarding this.

Yes. I suggest a slight modification to your checkViewer() return value to make the conditional check in your calling code less error prone:

class AppController extends Controller {
   //some code
   public function checkViewer() {
      if($this->Auth->user('type') != 3) {
         return $this->redirect(['controller' => 'Pages', 'action' => 'unauthorized']);
      }
      //I've change the return type here
      //   but you can use what you like as long as it matches 
      //   your conditionals in the calling code
      return null;
   }
}

Then your calling code must decide whether to return the redirect or continue with its own code:

class ProductsController extends AppController {
   public function checkProduct() {
      $redirect = $this->checkViewer();
      if (!is_null($redirect) {
         return $redirect;
      }
      // other code here
   }
   public function viewProduct() {
      $redirect = $this->checkViewer();
      if (!is_null($redirect) {
         return $redirect;
      }
      // other code here
   }
}

You could also work from the knowledge that $this->redirect() returns a response object. That would make your calling code look something like this:

   public function viewProduct() {
      $redirect = $this->checkViewer();
      if ($redirect instanceof Cake\Http\Response) {
         return $redirect;
      }
      // other code here
   }

The key point here is, the endpoint named in your url/request must return the redirect. If it calls another method to decide whether to redirect or not (as you do), simply returning from the second method will only take you back into your original calling code. That code must then return the redirect (if there is one).

1 Like