首先,这个问题建立在这里的问答基础上:修改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"来引用相关的模型。
它能很好地满足我的需求,希望其他人也能觉得它有用。我相信有不止一种方法可以完成这项工作,请随意添加任何有用的内容。