我想用拉威尔的Passport 来验证身份,但没办法...总是收到401的那名客户是无效的,我会把我try 过的留给你:

我的phpunit配置是来自基地的laravel配置

tests/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;
    }
}

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

My handy authentication with passport for testing purposes

路由/空气污染指数.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);
});

推荐答案

这就是你如何实现这一点,让它真正发挥作用.

首先,你应该正确地实现db:seedsPassport installation.

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

So here is a description, on how it worked in my installation (Laravel 5.5)...

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

幸运的是,这个示例还涵盖了Basic Passport authorization测试.

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

  1. Create passport keys on test setup.
  2. Seed db with users, roles and other resources which might be needed.
  3. Create .env entry with PASSPORT_CLIENT_ID (optional - Passport always create password grant token with id = 2 on empty db).
  4. 使用此id从数据库中获取正确的客户端密钥.
  5. And then run your tests...

代码示例...

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

Notes:

Credentials need to be modified of course.

PASSPORT_CLIENT_ID needs to be 2, as explained before.

JsonStructure verification is redundant, since we get 200 response, only if authorization succeeds. However, if you wanted additional verification, this also passes...

TestCase.php

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

Notes:

在这里,我们为db创建相关条目,这是我们的测试中需要的. 因此请记住,要在此处 seeder 具有角色等的用户.

Final notes...

This should be enough, to get your code working. On my system, all this passes green and also works on my gitlab CI runner.

Finally, please check your middlewares on routes also. Especially, if you were experimenting with dingo (or jwt by thymon) package.

The only middleware, you may consider, applying to Passport authorization route, is throttle to have some protection from brute force attack.

Side note...

Passport and dingo have totally different jwt implementations.

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

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

Laravel相关问答推荐

使用MAATWebSite/EXCEL导入Exel时,不会创建Laravel模型

如何在控制器中获取所需参数?

V-icon 在 Vuetify 3 中不显示图标

导出所有客户端不起作用,文件保存时没有名称和扩展名

Laravel:子文件夹中的 lang 文件

"public/index.php" 可以在 laravel 中按组写入

Laravel 5.3:语法错误或访问冲突:1463 HAVING 子句中使用了非分组字段距离

在laravel中将数据插入数据透视表

Laravel Eloquent,仅 Select 存在关系的行

验证规则 required_if 与其他条件(Laravel 5.4)

laravel 中的 Http Post 使用 fetch api 给出 TokenMismatchException

Laravel 4 的 Cron 作业(job)

Laravel 5.4 - 注册后禁用自动登录

如何在 Laravel 中创建类别的嵌套列表?

Laravel 5 干预中的图像验证

Laravel db 迁移 - renameColumn 错误 - 请求了未知的数据库类型枚举

日期验证 - 如何本地化/翻译字符串今天和明天

如何在 Laravel 中 Refresh刷新用户对象?

如何在 Laravel 5 中验证 RESTful API?

带有 Xdebug 的 Laravel 5 总是抛出The payload is invalid..