Laravel Passport - Тестирование пароля - PullRequest
0 голосов
/ 28 марта 2019

Я использую Laravel 5.7 вместе с Passport для создания API для первого клиента.У меня есть форма входа в систему, которая принимает электронную почту и пароль пользователя и отправляет оба на пользовательский LoginController.Затем LoginController создает полезную нагрузку oAuth, отправляет запрос POST на oauth/token через Guzzle и возвращает access_token, refresh_token и все остальное моему клиенту первого лица.

Все работает отлично, когда я тестирую его вбраузер.Однако теперь я хотел бы написать интеграционный тест для всего этого и столкнулся с проблемой.Проблема в том, что сервер oAuth продолжает отклонять мой клиент и / или запрос Guzzle, только во время тестирования.

Вот мой соответствующий код:

LoginController

<?php

namespace App\Http\Controllers\Api;

use App\Domain\Auth\PasswordGrant;
use App\Http\Requests\LoginRequest;

class LoginController extends ApiController
{
    /**
     * LoginController constructor.
     */
    public function __construct()
    {
        $this->middleware('api')->only('login');
    }

    /**
     * Attempt to authenticate the user with the credentials they provided
     * and if successful, return an access token for the user.
     *
     * @param LoginRequest $request
     * @return \Illuminate\Http\Response
     */
    public function login(LoginRequest $request)
    {
        return PasswordGrant::attempt($request->email, $request->password);
    }
}

PasswordGrant

<?php

namespace App\Domain\Auth;

use GuzzleHttp\Client as GuzzleHttp;
use GuzzleHttp\Exception\ClientException;
use Laravel\Passport\Client;

class PasswordGrant
{
    /**
     * The GuzzleHttp client instance.
     *
     * @var GuzzleHttp
     */
    protected $http;

    /**
     * PasswordGrant constructor.
     *
     * @param GuzzleHttp $http
     */
    public function __construct(GuzzleHttp $http)
    {
        $this->http = $http;
    }

    /**
     * @param $username
     * @param $password
     * @return \Illuminate\Http\Response
     */
    public static function attempt($username, $password)
    {
        $passwordGrant = resolve(static::class);

        $payload = $passwordGrant->oAuthPayload(
            $passwordGrant->oAuthClient(), $username, $password
        );

        return $passwordGrant->oAuthResponse($payload);
    }

    /**
     * Get the oAuth Client we are using to authenticate our login and user.
     *
     * @return Client
     */
    protected function oAuthClient()
    {
        return Client::query()
            ->where('name', config('api.password_client'))
            ->where('password_client', true)
            ->where('revoked', false)
            ->firstOrFail();
    }

    /**
     * The payload we need to send to our oAuth server in order to receive
     * a bearer token and authenticate the user.
     *
     * @param Client $client
     * @param $username
     * @param $password
     * @return array
     */
    protected function oAuthPayload(Client $client, $username, $password)
    {
        return [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => $client->id,
                'client_secret' => $client->secret,
                'username' => $username,
                'password' => $password,
                'scope' => '*'
            ]
        ];
    }

    /**
     * Get the response from our oAuth server.
     *
     * @param array $payload
     * @return \Illuminate\Http\Response
     */
    protected function oAuthResponse(array $payload)
    {
        try {

            return $this->http->post(route('passport.token'), $payload)->getBody();

        } catch (ClientException $exception) {

            return response($exception->getMessage(), $exception->getCode());

        }
    }
}

PasswordGrantTest

<?php

namespace Tests\Feature\Requests\Team;

use App\Domain\Auth\PasswordGrant;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Tests\TestCases\TestCase;

class PasswordGrantTest extends TestCase
{
    use RefreshDatabase;

    /** @test */
    public function it_returns_an_access_token_for_a_user_with_valid_credentials()
    {
        Artisan::call('passport:client', [
            '--password' => true,
            '--name' => config('api.password_client')
        ]);

        $user = create(User::class);

        $result = PasswordGrant::attempt($user->email, 'secret');

        dd($result);
    }
}

dd в конце моего теста всегда возвращает401 с сообщением: {"error":"invalid_client","message":"Client authentication failed"}

Я трижды проверил наличие и действительность моей модели пользователя, клиента паспорта и убедился, что полезная нагрузка сформирована правильно.

Почемуработает ли предоставление пароля, когда я тестирую его через браузер, но оно не работает при отправке того же запроса на сервер из моих тестов?

Возможно, в моем запросе отсутствуют некоторые заголовкина сервер во время тестирования?

...