当前位置: 首页 > 知识库问答 >
问题:

如何使用Laravel Passport通过API测试身份验证?

司空兴为
2023-03-14

我试图用Laravel的护照测试身份验证,没有办法...总是收到401的客户端是无效的,我会告诉你我试过什么:

我的phpunit配置是一个来自基地与拉威尔

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;
    }
}
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'
        ]);
    }
}

我方便的护照认证用于测试目的

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);
});

共有3个答案

寇开畅
2023-03-14

我认为选择的答案可能是迄今为止最健壮和最好的,但我想提供一个替代方案,如果你只需要快速通过护照后的测试,而无需太多的设置。

重要提示:我认为如果你要做很多这件事,这不是正确的方法,其他答案更好。但在我看来,这似乎只是工作

这里是一个完整的测试用例,我需要假设一个用户,发布到一个endpoint,并使用他们的授权令牌发出请求。

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

use App\Models\User;
use Laravel\Passport\Passport;

class MyTest extends TestCase
{
    use WithFaker, RefreshDatabase;

    public function my_test()
    {
        /**
        *
        * Without Artisan call you will get a passport 
        * "please create a personal access client" error
        */
        \Artisan::call('passport:install');

        $user = factory(User::class)->create();
        Passport::actingAs($user);

        //See Below
        $token = $user->generateToken();

        $headers = [ 'Authorization' => 'Bearer $token'];
        $payload = [
            //...
        ];



        $response = $this->json('POST', '/api/resource', $payload, $headers);

        $response->assertStatus(200)
                ->assertJson([
                    //...
                ]);

    }
}

为了清楚起见,这里是User模型中的GenerateToken()方法,它利用了HasApiTokens特性。

public function generateToken() {
    return $this->createToken('my-oauth-client-name')->accessToken; 
}

在我看来,这是相当粗糙和准备就绪的。例如,如果您使用的是ReFresDatabase特性,您必须在每个方法中运行这样的护照:安装命令。通过全局设置可能有更好的方法来做到这一点,但我对PHPUnit相当陌生,所以这就是我的做法(目前)。

聂翼
2023-03-14

Laravel Passport实际上附带了一些测试助手,您可以使用这些助手来测试经过身份验证的APIendpoint。

Passport::actingAs(
    factory(User::class)->create(),
);
司徒锐进
2023-03-14

这就是如何实现它,使它实际工作。

首先,您应该正确地实现db:seeds和Passport安装。

第二,您不需要创建自己的路径来验证,如果这样做有效的话(基本的Passport响应就足够了)。

下面是一个描述,关于它在我的安装(Laravel 5.5)中是如何工作的。。。

在我的例子中,我只需要一个Passport客户端,这就是为什么我创建了另一个路由,用于api授权(api/v1/login),只提供用户名和密码。你可以在这里了解更多。

幸运的是,这个示例还包括基本的Passport授权测试。

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

  1. 在测试设置中创建passport密钥。
  2. 为数据库添加用户、角色和其他可能需要的资源。
  3. 使用PASSPORT\u CLIENT\u ID创建.env条目(可选-PASSPORT始终使用空数据库上的ID=2创建密码授予令牌)。
  4. 使用此id从db获取正确的客户端密钥。
  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\u CLIENT\u ID必须为2。

JsonStructure验证是冗余的,因为只有在授权成功的情况下,我们才能得到200个响应。但是,如果您需要额外的验证,这也会通过。。。

TestCase.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跑步者。

最后,请在路线上检查您的中间件。特别是,如果你正在试验野狗(或thymon的jwt)包。

唯一可以考虑应用于护照授权路由的中间件是“代码>节流器< /代码>,以防止暴力攻击。

旁注...

Passport和dingo有完全不同的jwt实现。

在我的测试中,只有Passport的行为是正确的,我认为这就是为什么不再保留野狗的原因。

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

 类似资料:
  • 我们想使用Jitsi REST API创建一个会议。我们的Jitsi实例已经受到Prosody的保护:只有某些用户可以主持会议(他们必须使用用户和密码凭据进行身份验证才能主持会议室)。现在,在他们这么做之后,计划是通过创建一个来宾密码来保护房间,聊天伙伴/来宾需要输入该密码才能加入会议。这个过程需要通过REST API实现自动化:我们希望通过REST API创建会议,并传递一个需要来宾输入的密码。

  • 我正在我的Web应用程序中构建聊天功能。我使用jitsi作为我们的聊天服务器。在视频聊天会话中可以有2-4个用户。这些会话将被锁定。Web应用程序将启动聊天,并将控制谁可以加入聊天室。 我试图嵌入jitsi满足内部使用jitsi满足外部API的网页这里列出https://github.com/jitsi/jitsi-meet/blob/master/doc/api.md。 我们的jitsi会议不向

  • 在我配置了下面的配置之后,它不会连接到Active Directory。我无法使用Active Directory的帐户登录。会有什么问题? 我有一个Ubuntu服务器18.04,带有ApacheGuacamoleV1。0.0. 安装。我想使用LDAP身份验证来验证用户。我已经下载了鳄梨酱-auth-ldap-1.0.0。jar和jldap-4.3。jar扩展。 10.10.10.21,10.10

  • (我曾在SO上回顾过类似的问题,但没有一个建议对我有效) 我有一个API服务,运行在Google App Engine上(在Google云平台上)。我需要通过谷歌管理目录API的身份验证,以便我可以在我们的GSuite域上创建组。 我最初尝试了隐式授权,遵循指南,以手动获取和提供服务帐户凭据,但我认为这可能仅限于在Google App Engine上运行的应用程序之间的通信。我的理解是,在App

  • 问题内容: 我们有一个Java EE 7应用程序,并使用Arquillian进行测试。现在,我们要检查当前登录用户的某些权限。我的问题很基本,在测试用例中时如何登录用户?我已经阅读了ProgrammaticLogin在Arquillian测试和Embedded Glassfish,安全性和Arquillian问题中不起作用,但是并没有明确回答。我当前的方法是这样的: 现在,当我尝试运行此命令时,将