Laravel Passport-测试密码授予

时间:2019-03-28 00:12:43

标签: php laravel unit-testing oauth-2.0 phpunit

我正在使用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"}

我对用户模型(护照客户端)的存在和有效性进行了三重检查,并确保有效载荷的格式正确。

为什么通过浏览器测试密码授予时起作用,但是从测试向服务器发出相同请求时,密码授予却不起作用?

也许我在测试期间向服务器的请求中缺少某些标头?

0 个答案:

没有答案