用于Auth的Cakephp Custom Finder,带有相关模型

时间:2016-04-20 16:06:31

标签: php authentication cakephp

首先,这个问题建立在问答上:Modifying AuthComponent identify method

我正在尝试实现的是使用基于身份验证的SSL基于令牌的API访问。我有API前缀设置和工作,我已成功使用基本身份验证AS LONG为用户名&定义的字段密码在Tokens表中,如下所示:

public function initialize() {
    parent::initialize();
    $this->loadComponent('RequestHandler');
    $this->loadComponent('Auth', [
        'authenticate' => [
            'Basic' => [
                'fields' => ['username' => 'user_id', 'password' => 'app_key_hashed'],
                'userModel' => 'Tokens'
            ]
        ],
        'storage' => 'Memory',
        'unauthorizedRedirect' => false
    ]);
}

最终我想使用用户的电子邮件(来自用户模型)和app_key(来自令牌模型)进行身份验证。阅读完文档(以及上面链接的问题和答案)之后,我觉得我需要使用自定义查找器来实现它。所以我将上面的代码更改为:

public function initialize() {
    parent::initialize();
    $this->loadComponent('RequestHandler');
    $this->loadComponent('Auth', [
        'authenticate' => [
            'Basic' => [
                'fields' => ['username' => 'user.email', 'password' => 'app_key_hashed'],
                'userModel' => 'Tokens',
                'finder' => 'auth'
            ]
        ],
        'storage' => 'Memory',
        'unauthorizedRedirect' => false
    ]);
}

并在我的TokensTable.php中包含以下内容:

    /**
 * Custom finder for Auth
 */

public function findAuth(\Cake\ORM\Query $query, array $options) {
    $query->select(['id', 'user_id', 'app_key_hashed', 'Users.email'])
            ->where(['Tokens.inactive' => 0])
            ->contain(['Users']);

    return $query;
}

当我这样做时,返回消息是:

{
  "message": "SQLSTATE[42S22]: Column not found: 1054 Unknown column    'Tokens.user.email' in 'where clause'",
  "url": "/flight-ops/api/tokens",
  "code": 500
}

我觉得问题不在于自定义查找程序查找数据,而是在Auth组件过滤数据时。我对么?我错过了一些简单的事吗?我是否使用自定义查找器咆哮着正确的树?

我正在使用CakePHP 3.2.4。

感谢您的帮助!

以下是我的表格和关系:

class TokensTable extends Table
{

/**
 * Initialize method
 *
 * @param array $config The configuration for the Table.
 * @return void
 */
public function initialize(array $config)
{
    parent::initialize($config);

    $this->table('tokens');
    $this->displayField('id');
    $this->primaryKey('id');

    $this->addBehavior('Timestamp');

    $this->belongsTo('Users', [
        'foreignKey' => 'user_id'
    ]);
}
}

class UsersTable extends Table
{

/**
 * Initialize method
 *
 * @param array $config The configuration for the Table.
 * @return void
 */
public function initialize(array $config)
{
    parent::initialize($config);

    $this->table('users');
    $this->displayField('id');
    $this->primaryKey('id');

    $this->addBehavior('Timestamp');

    $this->hasOne('Tokens', [
        'foreignKey' => 'user_id'
    ]);
}
}

1 个答案:

答案 0 :(得分:2)

首先,感谢Chris在上面的评论中确认我正朝着正确的方向前进。我通过扩展BasicAuthenticate类完成了问题中的任务(实际上,我只是从BaseAuthenticate扩展了一个函数,但我想同时包含BasicAuthenticate,所以我扩展了该类)。

这是我的TokenBasicAuthenticate类:

namespace App\Auth;

use Cake\Auth\BasicAuthenticate;
use Cake\Network\Request;
use Cake\Network\Response;
use Cake\ORM\TableRegistry;

class TokenBasicAuthenticate extends BasicAuthenticate{

    protected function _query($username)
    {

        $config = $this->_config;
        $table = TableRegistry::get($config['userModel']);

        $query = $table->find()
                        ->where([$config['userModel'] . '.inactive' => 0])
                        ->contain([$config['relatedModel']])
                        ->matching($config['relatedModel'], function($q) use ($config, $username) {
                           return $q->where([$config['fields']['username'] => $username]) ;
                        });

        return $query;

    }
}

我还将Auth初始化更改为:

public function initialize() {
        parent::initialize();
        $this->loadComponent('RequestHandler');
        $this->loadComponent('Auth', [
            'authenticate' => [
                'TokenBasic' => [
                    'fields' => ['username' => 'Users.email', 'password' => 'app_key_hashed'],
                    'userModel' => 'Tokens',
                    'relatedModel' => 'Users',
                    'finder' => 'auth'
                ]
            ],
            'storage' => 'Memory',
            'unauthorizedRedirect' => false
        ]);
    }

如您所见,我添加了一个额外的字段'relatedModel'来引用相关模型。

它适合我的需求,希望其他人认为这很有用。我确信不止一种方法可以完成这个,随意添加任何有用的东西。