Cakephp用于Auth的自定义查找器,以及相关模型


Cakephp Custom Finder for Auth, with related model

首先,这个问题建立在这里的问答基础上:修改AuthComponent标识方法

我试图实现的是使用SSL上的基本验证对API进行基于令牌的访问。我有API前缀设置和工作,我已经成功地使用了基本身份验证,只要为username&密码在令牌表中,如下所示:

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
    ]);
}

最终,我想使用User的电子邮件(来自Users模型)和app_key(来自Tokens模型)进行身份验证。在阅读了文档(以及上面链接的问答)之后,我觉得我需要使用自定义查找器来实现这一点。所以我把上面的代码改为:

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'
    ]);
}
}

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

这是我的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"来引用相关的模型。

它能很好地满足我的需求,希望其他人也能觉得它有用。我相信有不止一种方法可以完成这项工作,请随意添加任何有用的内容。