【问题标题】:CakePHP 3.8 Authentication Plugin: FAILURE_CREDENTIALS_MISSINGCakePHP 3.8 身份验证插件:FAILURE_CREDENTIALS_MISSING
【发布时间】:2020-03-27 15:23:09
【问题描述】:

这是我第一次尝试在 Cake 3.8 中使用 Authentication 插件。我遵循了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-&gt;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 无法检测到帖子数据中是否存在凭据。其他人遇到同样的问题并有解决方案吗?

谢谢。

【问题讨论】:

  • 您发送什么类型的数据?表格数据? JSON? ...
  • 表单数据 - 作为键值对包含在帖子正文中。我已经编辑了上面的帖子以包含登录的角度代码。
  • 尝试在FormAuthenticator::_getData 中调试。当此函数返回 null 时,您看到的错误似乎会发生,这可能会以两种方式之一发生。应该很容易缩小范围。
  • 谢谢 Greg - 我确实做到了,发现 _getData() 确实在解析请求中的空值。在深入挖掘之后,我相信这是由于 Angular 发送数据的方式 - 当直接作为对象包含在帖子正文中时。相反,需要将数据(键值对)附加到 FormData 对象,并将其用作帖子的正文。添加在答案中。
  • 看起来您实际上是在发送 JSON,而不是表单数据。我对 Angular 并不太熟悉,但如果未另行指定,HTTP 客户端默认将原始对象作为 JSON 发送。

标签: authentication plugins cakephp-3.0 credentials missing-data


【解决方案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(application/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' )
                            }
)

希望这对以后遇到同样问题的人有所帮助。

【讨论】:

    【解决方案2】:

    为了在已经发布的可能解决方案之外详细说明这一点,当以非表单数据格式(即非application/x-www-form-urlencoded)发送数据时,例如 JSON(AFAICT 是使用 Angular 的 HTTP 客户端的原始对象的默认设置),您'将需要实现某种机制,将数据解码为 CakePHP 端相关代码可以读取/理解的格式,因为默认情况下 PHP 只解析表单数据。

    使用旧的 auth 组件对您有用,因为您很可能正在使用请求处理程序组件,该组件默认支持将 JSON 请求数据自动解码为可以从请求对象中检索到的常规数组样式的发布数据 ($request-&gt;getData() )。

    然而,新的身份验证插件在中间件​​级别运行身份验证,即在涉及任何控制器(以及因此组件)之前,因此身份验证中间件将无法访问解码数据,请求对象上的数据将为空(可以通过$request-&gt;input()获取原始JSON字符串)。

    为了使它工作,引入了正文解析器中间件,它可以做请求处理程序组件所做的事情,即解析原始输入数据,并用它填充常规请求数据。您将其放入身份验证中间件之前的队列中,禁用请求处理程序组件输入解码,然后它应该可以正常处理 JSON 数据:

    $middlewareQueue
        ->add(new \Cake\Http\Middleware\BodyParserMiddleware())
        ->add(new \Authentication\Middleware\AuthenticationMiddleware($this));
    
    $this->loadComponent('RequestHandler', [
        'inputTypeMap' => [],
        // ...
    ]);
    

    另见

    【讨论】:

      猜你喜欢
      • 2018-09-07
      • 2013-11-10
      • 1970-01-01
      • 2014-05-11
      • 1970-01-01
      • 1970-01-01
      • 2018-06-02
      • 2016-08-24
      • 2011-03-11
      相关资源
      最近更新 更多