laravel - 如何使用 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);
});
解决方案
这就是你如何实现它,让它真正起作用。
首先,您应该正确实施db:seeds和Passport 安装。
第二个,您不需要创建自己的路线来验证是否可行(基本的Passport响应就足够了)。
所以这里有一个描述,关于它在我的安装中是如何工作的(Laravel 5.5)......
在我的情况下,我只需要一个Passport客户端,这就是为什么我创建了另一个路由,用于 api 授权 ( api/v1/login
),只提供用户名和密码。你可以在这里阅读更多关于它的信息。
幸运的是,这个例子也涵盖了基本的Passport 授权测试。
因此,要成功运行测试,基本思想是:
- 在测试设置上创建护照密钥。
- 使用用户、角色和其他可能需要的资源播种数据库。
- 创建
.env
条目PASSPORT_CLIENT_ID
(可选 - Passport始终password grant token
在空数据库上创建 id = 2)。 - 使用此 id 从数据库中获取正确的 client_secret。
- 然后运行你的测试......
代码示例...
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
对暴力攻击有一些保护。
边注...
Passport和dingo有完全不同的jwt实现。
在我的测试中,只有Passport的行为是正确的,我认为这就是为什么不再维护dingo的原因。
希望它能解决你的问题...
推荐阅读
- flutter - Flutter GridView 图像放大缩小
- python - 导入python包时GSL未定义符号
- c# - 删除字符串中的所有正则表达式重合
- sql - 无法获取大于日期的数据
- git - 海量“空文件”。在 GitHub 拉取请求更改选项卡中
- firebase - Flutter Firebase:我需要将 firebase 实现添加到 build.gradle 吗?
- arrays - 如何检查两个数组中的所有元素是否相等(元素的顺序无关紧要)?
- c# - 如何使用循环做一个带根的算术序列
- sql - 如果存在则从一个表中选择,否则从另一个具有最新日期的表中选择
- javascript - 在 Vue 中挂载时访问 css 变量