Help with Authentication Plugin

Hi all,

This might be a dumb question but I’m trying to authenticate users of my site using the CakePHP authentication plugin, and I’m following the guide here: https://book.cakephp.org/authentication/1.1/en/index.html.
I’m confused about how I actually perform the action of authenticating someone. Say I have a table accounts with email and password fields that need to match up with the email and password entered in a form in the login page. What do I actually need to write in my controller to perform this authentication? Where do I tell it to use this table with these fields? Or am I doing this entirely wrong? Apologies if this is a dumb question, I’m very new to CakePHP.

Thanks!

With this plugin, you don’t write anything in your controller to do authentication. You add the code shown on that page to your Application class. By default, it uses the Users table; if that’s not right for your situation, see the documentation on Identifiers, in particular the ORM Resolver configuration.

Okay so I looked at that Identifiers page and I think I need to use that userModel option towards the end, but I have no idea where to put it. My table that I’m using is called Accounts.
The main thing I’m confused about is that when I have the form that submits the login details, how does the authentication middleware know that this specific form submission contains login details, and how does it know which field to match it up with in the database, and why don’t I need to pass the form data to some authentication function? I’m confused because I can’t visualise the flow of data.

The Identifiers documentation shows that the loadIdentifier call from the Quick Start page would be replaced with something like this:

$service->loadIdentifier('Authentication.Password', [
    'fields' => [
        'username' => 'email',
        'password' => 'passwd',
    ],
    'resolver' => [
        'className' => 'Authentication.Orm',
        'finder' => 'active'
    ],

The fields would obviously be set to whatever your field names are, so presumably “password” instead of “passwd” from what you wrote earlier. The ORM resolver documentation indicates that it can take finder and userModel parameters, so your version would add the latter:

    'resolver' => [
        'className' => 'Authentication.Orm',
        'finder' => 'active',
        'userModel' => 'Accounts',
    ],

Putting this all together, what you want will look like:

$service->loadIdentifier('Authentication.Password', [
    'fields' => [
        'username' => 'email',
        'password' => 'password',
    ],
    'resolver' => [
        'className' => 'Authentication.Orm',
        'finder' => 'active'
        'userModel' => 'Accounts',
    ],

As to how the middleware knows that this is a login post, that comes from the configuration of the Form authenticator. That can be set to tell it which URL handles logins, what the names of the fields are in the form (the resolver configuration above sets the names of the fields in the table, which doesn’t necessarily have to match), etc.

3 Likes

Alright, thanks so much for the help so far, I think I get it. Now it’s telling me that I have a CSRF mismatch when I try to log in, which I assume means I’ve put in my details incorrectly. This is what I have in my Application.php:

$service->loadIdentifier('Authentication.Password', [
    'fields' => [
    'username' => 'email',
    'password' => 'password',
],
    'resolver' => [
        'className' => 'Authentication.Orm',
        'userModel' => 'Accounts'
    ]
]);

// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
    'fields' => [
        'username' => 'email',
        'password' => 'password',
    ],
    'loginUrl' => '/client/login'
]);

I think this should work, the form is on the page client/login. This is how the form is constructed:

<form method="post">
        <div class="form-group has-feedback">
            <input type="email" class="form-control" placeholder="Email" name="email">
        </div>
        <div class="form-group has-feedback">
            <input type="password" class="form-control" placeholder="Password" name="password">
        </div>
        <div class="row">
            <!-- /.col -->
            <div class="col-xs-4">
                <button type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
            </div>
            <!-- /.col -->
        </div>
    </form>

And this is what’s in my controller:

public function login()
{
    $this->loadModel('Accounts');
    if ($this->request->is(['post', 'put'])) {
        $result = $this->Authentication->getResult();
        Debugger::dump($result);
    }
}

I’m not sure what I’m doing wrong to get this token mismatch. Thanks again for all of your help. Here’s a photo of the accounts table as well.

CSRF mismatch has nothing to do with your login process, and everything to do with how you’re creating your forms. It’s discussed at length in many posts on StackOverflow, and probably here.

1 Like

Alright I got that working. Are you sure that I don’t need to pass the data to the authentication function in any way? When I try to login and I check the authentication result it says it has no data:

object(Authentication\Authenticator\Result) {
[protected] _status => 'FAILURE_IDENTITY_NOT_FOUND'
[protected] _data => null
[protected] _errors => [
	'Password' => [[maximum depth reached]]
]
}

Are you certain I need to do absolutely nothing in the controller?

My login function starts with $result = $this->Authentication->getResult();, so all the handling of form data is done before that ever runs. Look at your posted data to make sure it’s as you expect it to be, and feel free to dig into the source of the form authenticator, ORM resolver, and password identifier. Chances are extremely good that it’s a simple configuration issue which will become obvious when you see what they are expecting and compare to what they’re getting at the various stages.

I figured it out, thanks for all your help.
The problem was that I didn’t have my paswords hashed in the database, I planned to do that later and I didn’t realise that the plugin hashes automatically.