ToX 82
ToX 82

Reputation: 1074

unauthorizedRedirect set to false, still redirecting

I'm writing some REST api for my cake 3.0 application, and I need to set $this->Auth->unauthorizedRedirect to false, as the manual says that this would prevent my application to redirect to login url for unauthorized requests.

http://api.cakephp.org/3.0/class-Cake.Auth.BasicAuthenticate.html

The problem is that I'm trying to set it in my Users controller, and it doesn't work:

class UsersController extends AppController {

public function initialize() {
    parent::initialize();
    $this->loadComponent('RequestHandler');
}

public function beforeFilter(Event $event) {
    parent::beforeFilter($event);
    $this->Auth->allow(['logout']);

    // Change the authentication mode when using REST api
    if(! $this->RequestHandler->accepts('html')) {
        $this->Auth->unauthorizedRedirect = false;

        $user = $this->Auth->identify();
        if ($user) {
            $this->Auth->setUser($user);
        }
    }
}

This scripts works fine as detecting if a user is actually registered, but fails when I try to use wrong authentication data, showing the login form instead of throwing an error. What am I doing wrong?

Upvotes: 0

Views: 1708

Answers (1)

ndm
ndm

Reputation: 60453

Authentication and authorization are two different things

You are mixing up authentication and authorization, that's two different things. Logging in a user is authentication, testing whether a logged in user is allowed to access a specific action is authorization.

So the unauthorized redirect configuration applies to logged in users when accessing actions.

Handling unauthenticated requests

What you are looking for, ie throw an exception on unauthenticated requests, is done by the basic authentication adapter by default, so I assume that you actually aren't using this adapter!?

So if you are using a different adapter, this behavior is best implemented in either your controller where you are trying to identify the user

$user = $this->Auth->identify();
if (!$user) {
    throw new ForbiddenException('Stop! Hammer time!');
} else {
    $this->Auth->setUser($user);
}

or, in case you want the exception to be thrown for every controller, in a custom authentication adapters unauthorized() method, which is being invoked on unauthenticated requests before executing possible redirects. Quote from the docs:

Cookbook > Authentication > Handling Unauthenticated Requests

When an unauthenticated user tries to access a protected page first the unauthenticated() method of the last authenticator in the chain is called. The authenticate object can handle sending response or redirection by returning a response object, to indicate no further action is necessary. Due to this, the order in which you specify the authentication provider in authenticate config matters.

If authenticator returns null, AuthComponent redirects user to login action. [...]

Here's a simple example that extends the form authentication handler:

src/Auth/MyCustomAuthenticate.php

namespace App\Auth;

use Cake\Auth\FormAuthenticate;
use Cake\Network\Exception\ForbiddenException;
use Cake\Network\Request;
use Cake\Network\Response;

class MyCustomAuthenticate extends FormAuthenticate
{
    public function unauthenticated(Request $request, Response $response)
    {
        if(!$request->accepts('text/html')) {
            throw new ForbiddenException('Ah ah ah! You didn\'t say the magic word!');
        }
    }
}

Controller

$this->loadComponent('Auth', [
    'authenticate' => [
        'MyCustom'
    ]
]);

See also

Upvotes: 4

Related Questions