FriendsOfCake/Authenticate

TokenAuthenticate & Auth – How do I determine the authenticated user?

t1mmen opened this issue · 6 comments

Hi,

I'm trying and failing to get TokenAuthenticate to behave as I expect. I am assuming that $this->Auth->user() should return the logged in user when logged in via TokenAuthenticate. Is this incorrect?

If this is correct behaviour, should I manually log the user in based on $this->request->header('Authorization-Token') in AppController::beforeFind() or similar?

Setup:

  • CakePHP 2.4.7
  • Latest Crud plugin
  • Latest Authenticate plugin

Relevant AppController.php's $component setup:

'Authenticate.Token' => [
    'parameter' => '_token', 
    'header' => 'Authorization-Token', 
    'fields' => [
        'username' => 'email',
        'password' => 'password',
        'token' => 'token',
    ],
    'continue' => true,
]

Sample query:

curl -X GET "http://localhost/myapp/whatever.json" \
     -H "Authorization-Token: MyTokenHere" \
     -m 30 \
     -v \

queryLog excerpt, shows that TokenAuthenticate::_findUser does indeed find the user as it should:

SELECT `User`.`etc` FROM `mydb`.`users` AS `User` WHERE `User`.`token` = 'MyTokenHere'    LIMIT 1",

Did the query return any queries at all?

Yes, but only after I remove my AppModel::beforeFind's scoping, that currently looks like this:

public function beforeFind($queryData) {
    $fields = $this->schema();
    if (!empty($fields['user_id']) && $this->alias != 'User') {
        $current_user = $this->getCurrentUser();
        $queryData['conditions'][$this->alias.'.user_id'] = $current_user['id'];
    }
    return $queryData;
}

function getCurrentUser() {

    $current_user = Configure::read('currentUser');

    if ($current_user) {
        return $current_user;
    } else {
        App::uses('CakeSession', 'Model/Datasource');
        $Session = new CakeSession();
        $user_id = $Session->read('Auth.User.id');

        if ($user_id) {
            App::uses('User', 'Model');
            $User = new User();

            $result = $User->find('first', [
                'conditions' => ['User.id' => $user_id],
                'contain' => ['Connection'],
                'recursive' => -1]);

            // Format similar to Auth using Auth's contain option.
            $user = $result['User'];
            unset($user['password']);
            unset($result['User']);

            $response = array_merge($user, $result);

            Configure::write('currentUser', $response);

            return $response;
        }
    }

    return false;

}

PS: I realize I might have to rework the above code to rely on something other than sessions once I get this working (pointers would be helpful if that's the case).

Better illustrating the issue, might be (from AppController):

public function beforeFilter() {

    debug($this->request->header('Authorization-Token')); // returns my auth token
    debug($this->Auth->user()); // returns 'null'

    parent::beforeFilter();
}

For stateless providers (which TokenAuthenticate is) AuthComponent checks for user in AuthComponent::start() which is called after Controller::beforeFilter() so debug($this->Auth->user()); in beforeFilter is going to return null.

Interesting!

How come my beforeFilter above works when logged in using MultiColumnAuthenticate and regular Auth? Either way, this is great news, as I'm able to get at $this->Auth->user() from controller actions now.

Any pointers as to the best way of getting hold of the user from Models?

How come my beforeFilter above works when logged in using MultiColumnAuthenticate and regular Auth?

Because MultiColumnAuthenticate is a stateful authentication provider so once you login the info is saved in session and Auth is able to retrieve that info from session when you call user() method.

Any pointers as to the best way of getting hold of the user from Models?

Pass the user record to a model by setting it as a property or method argument.

P.S. If you have more questions please use IRC, this issues tracker is not a help forum.