这是我在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)。凭证通过嵌入在请求正文中的发布请求发送。通过$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无法在发布数据中检测到凭据的存在。还有其他人遇到同样的问题并有解决方案吗?
谢谢。
答案 0 :(得分:1)
终于找到了问题。正如Greg Schmidt所建议的那样,在FormAuthenticator :: __ getData()内部添加一些调试步骤有助于解决该问题。我发现_getData()正在将一个空数组传递给身份验证器。
如果您看一下上面的Angular代码,我将用户名和密码直接包含在主体中动态创建的对象的一部分中
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()对象自动添加Content-Type(应用程序/ x-www-form-urlencoded或formdata)标头和内容边界。修改后的代码如下所示:
// 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' )
}
)
希望这可以帮助将来遇到相同问题的任何人。
答案 1 :(得分:1)
在以非形式数据格式(即非application/x-www-form-urlencoded
)(例如JSON)(Angular HTTP客户端使用AFAICT是原始对象的默认设置)发送数据时,除了已经发布的可能解决方案之外,还要详细说明这一点,您需要实现某种机制,将数据解码为CakePHP端所涉及的代码可以读取/理解的格式,因为默认情况下,PHP仅解析表单数据。
使用旧的auth组件对您有用,因为您很可能正在使用请求处理程序组件,该组件默认情况下支持将JSON请求数据自动解码为可以从请求对象中检索到的常规数组样式的帖子数据({{1 }}。
但是,新的身份验证插件在中间件级别上运行身份验证,也就是说,在涉及任何控制器(以及组件)之前,该身份验证中间件将无法访问已解码的数据,因此请求对象上的数据将为空(可以通过$request->getData()
获取原始JSON字符串)。
为了使此工作正常进行,引入了主体解析器中间件,它可以执行请求处理程序组件的工作,即解析原始输入数据,并用它填充常规请求数据。您可以将其放在身份验证中间件之前的队列中,禁用请求处理程序组件的输入解码,然后它应该可以很好地处理JSON数据:
$request->input()
$middlewareQueue
->add(new \Cake\Http\Middleware\BodyParserMiddleware())
->add(new \Authentication\Middleware\AuthenticationMiddleware($this));
另请参见