CakePHP 5:API访问令牌与数据库哈希令牌不匹配问题
API令牌认证问题:明文令牌无法匹配哈希令牌
问题描述
开发供第三方集成的API端点,要求使用API访问令牌认证。已实现令牌生成逻辑:生成明文public_token,用DefaultPasswordHasher哈希后得到token存入数据库,期望通过「明文令牌匹配数据库哈希令牌」的密码式验证完成认证,但目前仅使用哈希后的token值能成功认证,使用明文public_token时返回FAILURE_CREDENTIALS_MISSING错误。
现有实现代码
模型beforeSave事件
public function beforeSave(EventInterface $event) { $entity = $event->getData('entity'); if ($entity->isNew()) { $hasher = new DefaultPasswordHasher(); $entity->public_token = Security::hash(Security::randomBytes(32), 'sha256', false); $entity->token = $hasher->hash($entity->public_token); } return true; }
application.php配置
$authenticationService->loadIdentifier('Authentication.Token'); $authenticationService ->loadAuthenticator('Authentication.Token', [ 'queryParam' => 'token', 'header' => 'Authorization', 'tokenPrefix' => 'Bearer', ]);
AppController.php配置
$this->loadComponent('Authorization.Authorization'); $this->Authentication->setConfig('authenticate', [ 'Token' => [ 'feilds' =>[ 'password' => 'token' ], 'tokenField' => 'token', 'dataField' => 'token', 'resolver' => 'Authentication.Orm', 'hashAlgorithm' => 'sha256', ], ]);
UsersController.php的login方法
public function login() { $this->Authorization->skipAuthorization(); $result = $this->Authentication->getResult(); if($result->isValid()){ try { $this->Authorization->authorize($this->Authentication->getIdentity()->getOriginalData()); }catch(\Exception $ex){ $user = [ 'message' => 'you do not have the credential to access this api' ]; } $user = $result->getData(); }else{ $this->response =$this->response->withStatus(401); $user = [ 'message' => 'login Details incorrect' ]; pr($result); exit; } $this->set('user', $user); $this->viewBuilder()->setOption('serialize', 'user'); $this->viewBuilder()->setClassName("Json"); }
错误信息
调试返回结果:
Authentication\Authenticator\Result Object ( [_status:protected] => FAILURE_CREDENTIALS_MISSING [_data:protected] => [_errors:protected] => Array ( [0] => Login credentials not found ) )
令牌示例
数据库存储的令牌数据:
'token' => '$2y$10$QW2VLbNkxPIbHNhEMxy2qeNbx2/KI21ff0Hjku0mTYWOK245hOXea' 'public_token' => 'f2f7014286b2079d4e4877cd145ab3d7d3024ebaf8c438be231819448e7ab7b8'
目标请求方式
期望使用明文public_token访问API:
$http = new Client([ 'headers' => ['Authorization' => 'Bearer ' . 'f2f7014286b2079d4e4877cd145ab3d7d3024ebaf8c438be231819448e7ab7b8'] ]);
解决方案
问题根源
- 配置拼写错误:
'feilds'应为'fields',导致认证器无法识别密码字段配置。 - 认证逻辑不匹配:当前配置让认证器直接将明文令牌与数据库哈希
token字段做等值匹配,自然无法匹配;同时错误配置hashAlgorithm为sha256,但实际token字段是用DefaultPasswordHasher(bcrypt)生成的哈希,算法不一致。 - 未启用哈希验证:Token认证器默认直接匹配令牌,未启用密码式哈希验证逻辑。
修复步骤
1. 修正AppController配置
修正拼写错误,并启用哈希验证,与beforeSave中的哈希逻辑保持一致:
$this->loadComponent('Authorization.Authorization'); $this->Authentication->setConfig('authenticate', [ 'Token' => [ 'fields' => [ 'password' => 'token' // 指定数据库中存储哈希令牌的字段 ], 'tokenField' => 'token', 'resolver' => 'Authentication.Orm', // 启用哈希验证,使用与beforeSave一致的默认密码哈希器 'hashChecker' => true, 'hasher' => [ 'className' => 'Authentication.Default', ], ], ]);
移除
hashAlgorithm配置,因为我们使用的是bcrypt哈希而非sha256,与令牌生成逻辑对齐。
2. 调整application.php的标识符配置
明确指定标识符的令牌字段,确保逻辑一致:
$authenticationService->loadIdentifier('Authentication.Token', [ 'tokenField' => 'token', // 数据库中哈希令牌的字段 ]); $authenticationService->loadAuthenticator('Authentication.Token', [ 'queryParam' => 'token', 'header' => 'Authorization', 'tokenPrefix' => 'Bearer', ]);
3. 修复Login方法逻辑
修正Login方法中覆盖变量的问题,确保授权失败时返回正确提示:
public function login() { $this->Authorization->skipAuthorization(); $result = $this->Authentication->getResult(); if ($result->isValid()) { try { $this->Authorization->authorize($this->Authentication->getIdentity()->getOriginalData()); $user = $result->getData(); } catch (\Exception $ex) { $this->response = $this->response->withStatus(403); $user = ['message' => 'You do not have the credential to access this api']; } } else { $this->response = $this->response->withStatus(401); $user = ['message' => 'Login details incorrect']; } $this->set('user', $user); $this->viewBuilder() ->setOption('serialize', 'user') ->setClassName('Json'); }
测试验证
使用明文public_token发送请求,此时认证器会自动用DefaultPasswordHasher验证明文令牌与数据库中的token哈希值,完成认证流程。
内容的提问来源于stack exchange,提问作者mopo
相关产品推荐
相关产品推荐

