3

Hy guys!

I haven’t been using Cake from gen 2 so i am a bit stuck with all the new stuff. I added the Authentication Component to my project and it works fine (login/out/pass hash etc) but i can’t seem to find how to make only the “Admin” prefix to require Authentication.

In the old times was something “simple” like:

if($this->params[‘prefix’] == ‘admin’){
    $this->Auth->deny(’*’);
}
ndm
  • 59,784
  • 9
  • 71
  • 110
Riker
  • 33
  • 4

2 Answers2

5

While you could do something similar with the authentication plugin's authentication component, authentication is now performed at middleware level, that is before a controller is being invoked, hence it is probably best to avoid trying to authenticate a user in the first place when it's not actually needed.

Scope the middleware

With the authentication plugin there's a few way to handle this, the easiest way would probably be to apply the authentication middleware on routing level, so that it is scoped to your prefixed routes.

You'd just remove adding the middleware in your Application::middleware() method (src/Application.php), and instead add it in either your config/routes.php file, or your Application::routes() method, depending on where you're connecting your prefix route:

$routes->prefix('Admin', function (RouteBuilder $routes) {
    $routes->registerMiddleware(
        'auth',
        new \Authentication\Middleware\AuthenticationMiddleware($this)
    );
    $routes->applyMiddleware('auth');

    // ...
});

This way only the routes connected in that prefix are going have authentication applied.

Conditionally require an authenticated user

As a second step you'd still need to handle checking for the possibly authenticated user, so that your endpoints are actually protected. By default the authentication component will do automatically, so one way would be to load the authentication component only for the Admin prefix, for example in your AppController::initialize() method:

if ($this->request->getParam('prefix') === 'Admin') {
    $this->loadComponent('Authentication.Authentication');
}

Note the capital A in Admin! In CakePHP 4.x prefixes on are now camel cased, while the generated URLs are lower cased and dash separated!

See also

ndm
  • 59,784
  • 9
  • 71
  • 110
  • Thanks! I managed to make it work adding the middleware only for the admin route. `new \Authentication\Middleware\AuthenticationMiddleware($this)` $this had to be a new AuthenticationService(); And as you wrote it the middleware must be added before any other routes are connected for the prefix. – Riker Jan 21 '20 at 16:36
  • @ndm but is there any way that different prefix uses different Identity? my API is a prefix and my admin is another prefix, in admin must just use form and session and in API use jwt. – Neo Anderson Dec 01 '20 at 07:14
  • 1
    @NeoAnderson Sure, instead of passing `$this` to the authentication middleware constructor (which would cause the `getAuthenticationService()` method to be looked up later on), you can directly pass an instance of `\Authentication\AuthenticationService`, which you can configure accordingly in your different prefixes. Another option could be to inspect the request in `getAuthenticationService()` and configure the authentication service instance differently based on that. – ndm Dec 01 '20 at 13:35
0

I don't know if this is a conventional method, but it works.

In the callback method beforeFilter, in my global Appcontroller.php, I had this code:

public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        if($this->request->getParam('prefix') == 'Api') {
            $this->Authentication->allowUnauthenticated([$this->request->getParam('action')]);
        }

    }
}

It allows access to all methods of my prefix API.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Adrien
  • 1