我正在使用Laravel 5.7和Passport为第一方客户端创建API。我有一个登录表单,该表单接受用户的电子邮件和密码,并将两者都发送到自定义的LoginController。 LoginController然后创建一个oAuth有效负载,通过Guzzle向POST
发送一个oauth/token
请求,并将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"}
我对用户模型(护照客户端)的存在和有效性进行了三重检查,并确保有效载荷的格式正确。
为什么通过浏览器测试密码授予时起作用,但是从测试向服务器发出相同请求时,密码授予却不起作用?
也许我在测试期间向服务器的请求中缺少某些标头?