首页 > 解决方案 > 如何使用 Laravel Passport 通过 API 测试身份验证?

问题描述

我正在尝试使用 Laravel 的 Passport 测试身份验证,但没有办法......总是收到该客户端的 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);
});

标签: laraveltestinglaravel-5phpunitlaravel-passport

解决方案


这就是你如何实现它,让它真正起作用。

首先,您应该正确实施db:seedsPassport 安装

第二个,您不需要创建自己的路线来验证是否可行(基本的Passport响应就足够了)。

所以这里有一个描述,关于它在我的安装中是如何工作的(Laravel 5.5)......

在我的情况下,我只需要一个Passport客户端,这就是为什么我创建了另一个路由,用于 api 授权 ( api/v1/login),只提供用户名和密码。你可以在这里阅读更多关于它的信息。

幸运的是,这个例子也涵盖了基本的Passport 授权测试。

因此,要成功运行测试,基本思想是:

  1. 在测试设置上创建护照密钥。
  2. 使用用户、角色和其他可能需要的资源播种数据库。
  3. 创建.env条目PASSPORT_CLIENT_ID(可选 - Passport始终password grant token在空数据库上创建 id = 2)。
  4. 使用此 id 从数据库中获取正确的 client_secret。
  5. 然后运行你的测试......

代码示例...

ApiLoginTest.php

/**
* @group apilogintests
*/    
public function testApiLogin() {
    $body = [
        'username' => 'admin@admin.com',
        'password' => 'admin'
    ];
    $this->json('POST','/api/v1/login',$body,['Accept' => 'application/json'])
        ->assertStatus(200)
        ->assertJsonStructure(['token_type','expires_in','access_token','refresh_token']);
}
/**
 * @group apilogintests
 */
public function testOauthLogin() {
    $oauth_client_id = env('PASSPORT_CLIENT_ID');
    $oauth_client = OauthClients::findOrFail($oauth_client_id);

    $body = [
        'username' => 'admin@admin.com',
        'password' => 'admin',
        'client_id' => $oauth_client_id,
        'client_secret' => $oauth_client->secret,
        'grant_type' => 'password',
        'scope' => '*'
    ];
    $this->json('POST','/oauth/token',$body,['Accept' => 'application/json'])
        ->assertStatus(200)
        ->assertJsonStructure(['token_type','expires_in','access_token','refresh_token']);
}

笔记:

凭证当然需要修改。

PASSPORT_CLIENT_ID 需要为 2,如前所述。

JsonStructure 验证是多余的,因为我们得到 200 响应,前提是授权成功。但是,如果您想要额外的验证,这也可以通过......

测试用例.php

public function setUp() {
    parent::setUp();
    \Artisan::call('migrate',['-vvv' => true]);
    \Artisan::call('passport:install',['-vvv' => true]);
    \Artisan::call('db:seed',['-vvv' => true]);
}

笔记:

在这里,我们正在为 db 创建相关条目,这些条目在我们的测试中是必需的。所以请记住,让具有角色等的用户在这里播种。

最后的笔记...

这应该足以让您的代码正常工作。在我的系统上,所有这些都通过了绿色并且也适用于我的 gitlab CI 运行器。

最后,请检查路由上的中间件。特别是,如果您正在尝试使用dingo(或thymon 的 jwt)包。

您可以考虑的唯一中间件,应用于Passport授权路由,是throttle暴力攻击有一些保护。

边注...

Passportdingo有完全不同的jwt实现。

在我的测试中,只有Passport的行为是正确的,我认为这就是为什么不再维护dingo的原因。

希望它能解决你的问题...


推荐阅读