Я использую 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"}
Я трижды проверил наличие и действительность моей модели пользователя, клиента паспорта и убедился, что полезная нагрузка сформирована правильно.
Почемуработает ли предоставление пароля, когда я тестирую его через браузер, но оно не работает при отправке того же запроса на сервер из моих тестов?
Возможно, в моем запросе отсутствуют некоторые заголовкина сервер во время тестирования?