CakePHP 3.8 身份验证插件:FAILURE_CREDENTIALS_MISSING
CakePHP 3.8 Authentication Plugin: FAILURE_CREDENTIALS_MISSING
这是我第一次尝试在 Cake 3.8 中使用身份验证插件。我遵循了 https://book.cakephp.org/authentication/1/en/index.html.
中概述的示例
Angular / Typescript 向 Cake 发送凭据的代码:
/**
* Login
*/
public login( username : string,
password : string,
captchaResponse : string ) {
return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
{
username,
password,
captchaResponse
},
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
}
).pipe( map( response => {
// Store user details and jwt token in local storage
// to keep user logged in between page refreshes
this.user = response.data;
this.setUser( this.user.profile );
this.setToken( this.user.token );
return this.user;
} ) );
}
在Application.php
public function bootstrap() {
// Authentication
$this->addPlugin( 'Authentication' );
}
/**
* Returns a service provider instance.
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request
* @param \Psr\Http\Message\ResponseInterface $response Response
* @return \Authentication\AuthenticationServiceInterface
*/
public function getAuthenticationService( ServerRequestInterface $request, ResponseInterface $response ) {
$service = new AuthenticationService();
// Load identifiers
$service->loadIdentifier( 'Authentication.Password', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'resolver' => [
'className' => 'Authentication.Orm',
'finder' => 'active',
'userModel' => 'Users',
],
] );
// Load the authenticators
$service->loadAuthenticator( 'Authentication.Form', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'loginUrl' => '/users/token.json'
] );
$service->loadIdentifier( 'Authentication.JwtSubject' );
// Configure the service. (see below for more details)
return $service;
}
public function middleware( $middlewareQueue ) {
$middlewareQueue
// Authentication Middleware
->add( new AuthenticationMiddleware( $this ) );
return $middlewareQueue;
}
在AppController.php
// Authentication Component
$this->loadComponent( 'Authentication.Authentication' );
我正在从 Angular 7 应用程序向 Cake(充当 REST API)发送凭据。信用通过嵌入在请求正文中的 post 请求发送。当我通过 $result->isValid()
.
检查时,我一直收到无效的身份验证结果
在UsersController.php中,当我尝试跟踪错误时:
$this->log( $this->request->getData(), 'debug' );
$result = $result = $this->Authentication->getResult();
$this->log( $result, 'debug' );
我得到以下输出:
2019-12-03 07:35:30 Debug: Array
(
[username] => myuser
[password] => mypassword
[captchaResponse] =>
)
2019-12-03 07:35:30 Debug: Authentication\Authenticator\Result Object
(
[_status:protected] => FAILURE_CREDENTIALS_MISSING
[_data:protected] =>
[_errors:protected] => Array
(
[0] => Login credentials not found
)
)
我只是想不通为什么 Cake 无法检测到 post 数据中是否存在凭据。还有其他人遇到同样的问题并有解决方案吗?
谢谢。
终于找到问题了。正如 Greg Schmidt 所建议的那样,在 FormAuthenticator::_getData() 中添加一些调试步骤有助于解决问题。我发现 _getData() 将空数组传递给验证器。
如果您查看上面的 Angular 代码,我直接将用户名和密码作为动态创建的 object 的一部分包含在 body:
中
return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
// NOT THE RIGHT WAY OF DOING IT
{
username,
password,
captchaResponse
},
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
}
)
出于某种原因,新的 FormAuthenticator / Authetication 插件无法解析此信息 - 尽管 这不是旧 AuthComponent 的问题。
相反,我不得不修改 Angular 代码以利用 FormData() object 自动添加 Content-Type(application/x-www-form-urlencoded 或表单数据)header 和内容边界。修改后的代码如下:
// Prepare form data
const formData = new FormData();
formData.append( 'username', username );
formData.append( 'password', password );
formData.append( 'captcha', captchaResponse );
return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
formData,
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
.set( 'Accept', 'application/json' )
.set( 'Cache-Control', 'no-cache' )
}
)
希望这对以后遇到同样问题的人有所帮助。
在以非表单数据格式发送数据时,即非application/x-www-form-urlencoded
,例如JSON(AFAICT是 Angular 的 HTTP 客户端的原始对象的默认值),你需要实现某种机制,将数据解码成 CakePHP 端的相关代码可以 read/understand,默认情况下 PHP 只解析表单数据。
使用旧的 auth 组件它对你有用,因为你很可能正在使用请求处理程序组件,默认情况下它支持自动将 JSON 请求数据解码为常规数组样式 post 数据可以从请求对象中检索 ($request->getData()
).
然而,新的身份验证插件在中间件级别运行身份验证,即在涉及任何控制器(以及组件)之前,因此身份验证中间件将无法访问解码数据,请求对象上的数据将为空(原始 JSON 字符串可以通过 $request->input()
获得)。
为了让它工作,引入了主体解析器中间件,它可以做请求处理程序组件所做的事情,即解析原始输入数据,并用它填充常规请求数据。您将它放在身份验证中间件之前的队列中,禁用请求处理程序组件输入解码,然后它应该可以很好地处理 JSON 数据:
$middlewareQueue
->add(new \Cake\Http\Middleware\BodyParserMiddleware())
->add(new \Authentication\Middleware\AuthenticationMiddleware($this));
$this->loadComponent('RequestHandler', [
'inputTypeMap' => [],
// ...
]);
另见
这是我第一次尝试在 Cake 3.8 中使用身份验证插件。我遵循了 https://book.cakephp.org/authentication/1/en/index.html.
中概述的示例Angular / Typescript 向 Cake 发送凭据的代码:
/**
* Login
*/
public login( username : string,
password : string,
captchaResponse : string ) {
return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
{
username,
password,
captchaResponse
},
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
}
).pipe( map( response => {
// Store user details and jwt token in local storage
// to keep user logged in between page refreshes
this.user = response.data;
this.setUser( this.user.profile );
this.setToken( this.user.token );
return this.user;
} ) );
}
在Application.php
public function bootstrap() {
// Authentication
$this->addPlugin( 'Authentication' );
}
/**
* Returns a service provider instance.
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request
* @param \Psr\Http\Message\ResponseInterface $response Response
* @return \Authentication\AuthenticationServiceInterface
*/
public function getAuthenticationService( ServerRequestInterface $request, ResponseInterface $response ) {
$service = new AuthenticationService();
// Load identifiers
$service->loadIdentifier( 'Authentication.Password', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'resolver' => [
'className' => 'Authentication.Orm',
'finder' => 'active',
'userModel' => 'Users',
],
] );
// Load the authenticators
$service->loadAuthenticator( 'Authentication.Form', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'loginUrl' => '/users/token.json'
] );
$service->loadIdentifier( 'Authentication.JwtSubject' );
// Configure the service. (see below for more details)
return $service;
}
public function middleware( $middlewareQueue ) {
$middlewareQueue
// Authentication Middleware
->add( new AuthenticationMiddleware( $this ) );
return $middlewareQueue;
}
在AppController.php
// Authentication Component
$this->loadComponent( 'Authentication.Authentication' );
我正在从 Angular 7 应用程序向 Cake(充当 REST API)发送凭据。信用通过嵌入在请求正文中的 post 请求发送。当我通过 $result->isValid()
.
在UsersController.php中,当我尝试跟踪错误时:
$this->log( $this->request->getData(), 'debug' );
$result = $result = $this->Authentication->getResult();
$this->log( $result, 'debug' );
我得到以下输出:
2019-12-03 07:35:30 Debug: Array
(
[username] => myuser
[password] => mypassword
[captchaResponse] =>
)
2019-12-03 07:35:30 Debug: Authentication\Authenticator\Result Object
(
[_status:protected] => FAILURE_CREDENTIALS_MISSING
[_data:protected] =>
[_errors:protected] => Array
(
[0] => Login credentials not found
)
)
我只是想不通为什么 Cake 无法检测到 post 数据中是否存在凭据。还有其他人遇到同样的问题并有解决方案吗?
谢谢。
终于找到问题了。正如 Greg Schmidt 所建议的那样,在 FormAuthenticator::_getData() 中添加一些调试步骤有助于解决问题。我发现 _getData() 将空数组传递给验证器。
如果您查看上面的 Angular 代码,我直接将用户名和密码作为动态创建的 object 的一部分包含在 body:
中return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
// NOT THE RIGHT WAY OF DOING IT
{
username,
password,
captchaResponse
},
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
}
)
出于某种原因,新的 FormAuthenticator / Authetication 插件无法解析此信息 - 尽管 这不是旧 AuthComponent 的问题。
相反,我不得不修改 Angular 代码以利用 FormData() object 自动添加 Content-Type(application/x-www-form-urlencoded 或表单数据)header 和内容边界。修改后的代码如下:
// Prepare form data
const formData = new FormData();
formData.append( 'username', username );
formData.append( 'password', password );
formData.append( 'captcha', captchaResponse );
return this.http.post<any>( 'http://api.mydomain.localhost/users/token.json',
formData,
{
headers : new HttpHeaders()
.set( 'X-Requested-With', 'XMLHttpRequest' )
.set( 'Accept', 'application/json' )
.set( 'Cache-Control', 'no-cache' )
}
)
希望这对以后遇到同样问题的人有所帮助。
在以非表单数据格式发送数据时,即非application/x-www-form-urlencoded
,例如JSON(AFAICT是 Angular 的 HTTP 客户端的原始对象的默认值),你需要实现某种机制,将数据解码成 CakePHP 端的相关代码可以 read/understand,默认情况下 PHP 只解析表单数据。
使用旧的 auth 组件它对你有用,因为你很可能正在使用请求处理程序组件,默认情况下它支持自动将 JSON 请求数据解码为常规数组样式 post 数据可以从请求对象中检索 ($request->getData()
).
然而,新的身份验证插件在中间件级别运行身份验证,即在涉及任何控制器(以及组件)之前,因此身份验证中间件将无法访问解码数据,请求对象上的数据将为空(原始 JSON 字符串可以通过 $request->input()
获得)。
为了让它工作,引入了主体解析器中间件,它可以做请求处理程序组件所做的事情,即解析原始输入数据,并用它填充常规请求数据。您将它放在身份验证中间件之前的队列中,禁用请求处理程序组件输入解码,然后它应该可以很好地处理 JSON 数据:
$middlewareQueue
->add(new \Cake\Http\Middleware\BodyParserMiddleware())
->add(new \Authentication\Middleware\AuthenticationMiddleware($this));
$this->loadComponent('RequestHandler', [
'inputTypeMap' => [],
// ...
]);
另见