Как проверить аутентификацию через API с помощью Laravel Passport?

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

моя конфигурация phpunit-это та, которая исходит из базы с laravel

тесты / TestCase.в PHP

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, DatabaseTransactions;

    protected $client, $user, $token;

    public function setUp()
    {
        parent::setUp();

        $clientRepository = new ClientRepository();
        $this->client = $clientRepository->createPersonalAccessClient(
            null, 'Test Personal Access Client', '/'
        );
        DB::table('oauth_personal_access_clients')->insert([
            'client_id' => $this->client->id,
            'created_at' => date('Y-m-d'),
            'updated_at' => date('Y-m-d'),
        ]);
        $this->user = User::create([
            'id' => 1,
            'name' => 'test',
            'lastname' => 'er',
            'email' => 'test@test.test',
            'password' => bcrypt('secret')
        ]);
        $this->token = $this->user->createToken('TestToken', [])->accessToken;
    }
}

тесты / функция / AuthTest.в PHP

class AuthTest extends TestCase
{
    use DatabaseMigrations;

    public function testShouldSignIn()
    {
        // Arrange
        $body = [
            'client_id' => (string) $this->client->id,
            'client_secret' => $this->client->secret,
            'email' => 'test@test.test',
            'password' => 'secret',
        ];
        // Act
        $this->json('POST', '/api/signin', $body, ['Accept' => 'application/json'])
        // Assert
        ->assertStatus(200)
        ->assertJsonStructure([
            'data' => [
                'jwt' => [
                    'access_token',
                    'expires_in',
                    'token_type',
                ]
            ],
            'errors'
        ]);
    }
}

моя удобная аутентификация с паспортом для целей тестирования

маршруты / api.в PHP

Route::post('/signin', function () {
    $args = request()->only(['email', 'password', 'client_id', 'client_secret']);
    request()->request->add([
        'grant_type' => 'password',
        'client_id' => $args['client_id'] ?? env('PASSPORT_CLIENT_ID', ''),
        'client_secret' => $args['client_secret'] ?? env('PASSPORT_CLIENT_SECRET', ''),
        'username' => $args['email'],
        'password' => $args['password'],
        'scope' => '*',
    ]);
    $res = Route::dispatch(Request::create('oauth/token', 'POST'));
    $data = json_decode($res->getContent());
    $isOk = $res->getStatusCode() === 200;
    return response()->json([
        'data' => $isOk ? [ 'jwt' => $data ] : null,
        'errors' => $isOk ? null : [ $data ]
    ], 200);
});

4 ответов


вот как вы можете реализовать это,чтобы заставить его работать.

прежде всего, вы должны правильно осуществить db: семена и установка паспорт.

Второй, вам не нужно, чтобы создать свой собственный маршрут для проверки, если это работает (basic паспорт ответы достаточно хороши, для этого).

Итак, вот описание того, как он работал в моей установке (Laravel 5.5)...

в моем случае, я нужен только один паспорт клиент, поэтому я создал другой маршрут для авторизации api (api/v1/login), чтобы указать только имя пользователя и пароль. Вы можете прочитать больше об этом здесь.

к счастью, этот пример охватывает basic разрешение на паспортмы создаем соответствующие записи в БД, которые необходимы в наших тестах. Так что помните, чтобы иметь пользователей с ролями так далее. посеян здесь.

финальные ноты...

этого должно быть достаточно, чтобы получить рабочий код. В моей системе все это проходит зеленым цветом, а также работает на моем GitLab CI runner.

наконец, пожалуйста, проверьте свои промежуточные программы на маршрутах также. Особенно, если вы экспериментировали с динго (или jwt by thymon пакет).

единственное промежуточное ПО, которое вы можете рассмотреть, применяя к паспорт авторизация маршрута, есть throttle иметь некоторую защиту от перебора.

Примечание...

паспорт и динго другое JWT в реализаций.

в моих тестах, только паспорт ведет себя правильно, и я предполагаю, что это причина, почему динго больше не поддерживается.

надеюсь, что это будет решать твоя проблема...


Что Laravel Паспорт на самом деле поставляется с некоторыми помощниками тестирования который можно использовать для проверки подлинности конечных точек API.

Passport::actingAs(
    factory(User::class)->create(),
);

Я не был знаком с инструментом паспорта, на который ссылается Дуайт, когда я писал это, так что, возможно, это более простое решение. Но есть кое-что, что может помочь. Он создает токен для вас, который вы можете применить к вашему вызову mock-API.

/**
 * @param Authenticatable $model
 * @param array $scope
 * @param bool $personalAccessToken
 * @return mixed
 */
public function makeOauthLoginToken(Authenticatable $model = null, array $scope = ['*'], $personalAccessToken = true)
{
    $tokenName = $clientName = 'testing';
    Artisan::call('passport:client', ['--personal' => true, '--name' => $clientName]);
    if (!$personalAccessToken) {
        $clientId = app(Client::class)->where('name', $clientName)->first(['id'])->id;
        Passport::$personalAccessClient = $clientId;
    }
    $userId = $model->getKey();
    return app(PersonalAccessTokenFactory::class)->make($userId, $tokenName, $scope)->accessToken;
}

тогда вы просто примените его к заголовкам:

$user = app(User::class)->first($testUserId);
$token = $this->makeOauthLoginToken($user);
$headers = ['authorization' => "Bearer $token"];
$server = $this->transformHeadersToServerVars($headers);

$body = $cookies = $files = [];
$response = $this->call($method, $uri, $body, $cookies, $files, $server);

$content = $response->getContent();
$code = $response->getStatusCode();

Если вам нужно иметь возможность анализировать токен, попробуйте следующее:

/**
 * @param string $token
 * @param Authenticatable $model
 * @return Authenticatable|null
 */
public function parsePassportToken($token, Authenticatable $model = null)
{
    if (!$model) {
        $provider = config('auth.guards.passport.provider');
        $model = config("auth.providers.$provider.model");
        $model = app($model);
    }
    //Passport's token parsing is looking to a bearer token using a protected method.  So a dummy-request is needed.
    $request = app(Request::class);
    $request->headers->add(['authorization' => "Bearer $token"]);
    //Laravel\Passport\Guards\TokenGuard::authenticateViaBearerToken() expects the user table to leverage the
    //HasApiTokens trait.  If that's missing, a query macro can satisfy its expectation for this method.
    if (!method_exists($model, 'withAccessToken')) {
        Builder::macro('withAccessToken', function ($accessToken) use ($model) {
            $model->accessToken = $accessToken;
            return $this;
        });
        /** @var TokenGuard $guard */
        $guard = Auth::guard('passport');
        return $guard->user($request)->getModel();
    }
    /** @var TokenGuard $guard */
    $guard = Auth::guard('passport');
    return $guard->user($request);
}

для тестирования паспорта вам не нужно идти на реального пользователя и пароль вы можете создать тест один.
Вы можете использовать Passport::actingAs или setup().

на actingAs вы можете сделать как

public function testServerCreation()
{
    Passport::actingAs(
        factory(User::class)->create(),
        ['create-servers']
    );

    $response = $this->post('/api/create-server');

    $response->assertStatus(200);
}

и setUp() вы можете достичь этого с помощью

public function setUp()
    {
        parent::setUp();
        $clientRepository = new ClientRepository();
        $client = $clientRepository->createPersonalAccessClient(
            null, 'Test Personal Access Client', $this->baseUrl
        );
        DB::table('oauth_personal_access_clients')->insert([
            'client_id' => $client->id,
            'created_at' => new DateTime,
            'updated_at' => new DateTime,
        ]);
        $this->user = factory(User::class)->create();
        $token = $this->user->createToken('TestToken', $this->scopes)->accessToken;
        $this->headers['Accept'] = 'application/json';
        $this->headers['Authorization'] = 'Bearer '.$token;
    }

вы можете получить более подробную информацию здесь и https://laravel.com/docs/5.6/passport#testing.