Best practice: Suppress unreachable links

I am writing an application that uses authentication and authorization. Authorization is done in a component based on controller and action invoked.
In my pages I want to suppress links the user cannot reach because he is not authorized. Is there a best practice on how to do that?

Calling the component from the View (in a Helper respectively) does work (that’s the route I’ve taken in the past), however I understand that his kind of breaks the MVC approach.
Of course I could just copy the code into the helper, but as this breaks DRY I would not want to do that at all.

Any suggestions on how to implement this in a neat way?

I’m doing it in other way, I have simple and custom RBAC.

To a user I can assign (I store that in table) combination of role + model + model_id eg:
user_id = 10, role = Team Manager , model = Teams , model_id = 20 ( 10 will be a Team Manager for = 20)

The other table defines role permissions per model and context eg:
role = Team Manager, model = Team, context = null , c = 0, r = 1 , u = 1 , d = 0 // Team Manager can read and update team but can’t create new teams or delete existing teams.

role = Team Manager, model = Team, context = Players , c = 1, r = 1 , u = 1 , d = 1 - Team manager can create, read, update and delete team players.

I have behavior that I attach to a model - for an example Team - which filters out records which user can’t read , this is used mostly on paginated lists: Team Manager can access only his teams.

When user is accessing edit page I know his id, model to which accessed record belongs to and record id - so I have all I need to build simple permission array which can look like :

$perms = [‘c’ => 0 , ‘r’ => 1, ‘u’ => 1 , ‘d’ => 0 , ‘Players’ => [ ‘c’ => 1 , ‘r’ => 1, ‘u’ => 1, ‘d’ => 1] ];

I generate this array in controller, then I pass it to helper (also in controller), in views I’m making checks like :

if ($this->User->canCreate()) { } if ($this->User->canRead()) { } ; if ($this->User->canDelete(‘Players’)) { }

Depends on feature against I’m doing checks I can hide or disable link.

On top of this I use AuthorisationMiddleware which reads configuration I have to create per controller, and which may look like (it also should be stored in db) :

protected static $authRules = [
    '_whiteListed' => ['index'],
    '_redirect' => ['action' => 'index'],
    'edit' => [
        ['model' => 'Teams', 'crud' => 'r', 'model_id' => 'params.pass.0', 'requestType' => 'get'],
    'delete' => [
        ['model' => 'Teams', 'crud' => 'd', 'model_id' => 'data.team_id', 'requestType' => 'ajax'],
    'deletePlayer' => [
        ['model' => 'Teams.Players', 'crud' => 'd', 'model_id' => 'data.team_id', 'requestType' => 'ajax'],

When user is accessing action that is not listed in above array, or user is accessing action which he is not allowed to or request type is other then allowed then Middleware is redirecting user to what is defined in _redirect.

This allows me to plug /remove authorization on top of any controller / model without refactoring actual code ( avoid in models and controllers if() {} … elseif() {} … else() {} …). Only views have to be slightly altered. When I remove authorization and I do not have a time to alter view , then I load helper that for all $this->User->canCRUD() returns always true.

Middleware allows me to mitigate unauthorized requests before they get to destination controller.

I’ve handled this in the past by extending the HTML helper and calling the permission checking code from there. I’m not sure if that works well in the policy-driven middleware plugin version of authorization.