From 75d31bc37dae4291db608849cd673f30ce2b1cd5 Mon Sep 17 00:00:00 2001 From: Clint Winter Date: Fri, 7 Jan 2022 15:01:39 -0500 Subject: [PATCH 1/4] Keyable scope --- composer.json | 17 +++-- src/Http/Middleware/EnforceKeyableScope.php | 70 +++++++++++++++++ src/KeyableServiceProvider.php | 36 +++++++-- tests/Feature/AuthenticateApiKey.php | 39 ++++++++++ tests/Feature/EnforceKeyableScope.php | 57 ++++++++++++++ tests/Support/Account.php | 16 ++++ .../create_accounts_and_posts_tables.php | 28 +++++++ tests/Support/Post.php | 14 ++++ tests/TestCase.php | 75 +++++++++++++++++++ 9 files changed, 339 insertions(+), 13 deletions(-) create mode 100644 src/Http/Middleware/EnforceKeyableScope.php create mode 100644 tests/Feature/AuthenticateApiKey.php create mode 100644 tests/Feature/EnforceKeyableScope.php create mode 100644 tests/Support/Account.php create mode 100644 tests/Support/Migrations/create_accounts_and_posts_tables.php create mode 100644 tests/Support/Post.php create mode 100644 tests/TestCase.php diff --git a/composer.json b/composer.json index 0ccf841..7e60207 100644 --- a/composer.json +++ b/composer.json @@ -3,8 +3,8 @@ "description": "Add API keys to your Laravel models", "license": "MIT", "keywords": [ - "laravel", - "php", + "laravel", + "php", "api", "rest", "json", @@ -21,15 +21,20 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": "^7.0|^8.0" + "php": "^7.0|^8.0", + "orchestra/testbench": "^6.23", + "phpunit/phpunit": "^9.5" }, - "require-dev": { - }, "autoload": { "psr-4": { "Givebutter\\LaravelKeyable\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Givebutter\\Tests\\": "tests/" + } + }, "extra": { "laravel": { "providers": [ @@ -37,4 +42,4 @@ ] } } -} \ No newline at end of file +} diff --git a/src/Http/Middleware/EnforceKeyableScope.php b/src/Http/Middleware/EnforceKeyableScope.php new file mode 100644 index 0000000..f4aafaa --- /dev/null +++ b/src/Http/Middleware/EnforceKeyableScope.php @@ -0,0 +1,70 @@ +route(); + + if (empty($route->parameterNames())) { + return $next($request); + } + + + $parameterName = $route->parameterNames()[0]; + $parameter = $route->parameters()[$parameterName]; + + if (! is_object($parameter)) { + $parameter = Arr::first($route->signatureParameters(UrlRoutable::class)); + $instance = app(Reflector::getParameterClassName($parameter)); + + $routeBindingMethod = $route->allowsTrashedBindings() + ? 'resolveSoftDeletableRouteBinding' + : 'resolveRouteBinding'; + + $instance->{$routeBindingMethod}($parameter, $route->bindingFieldFor($parameterName)); + } + + $childRouteBindingMethod = $route->allowsTrashedBindings() + ? 'resolveSoftDeletableChildRouteBinding' + : 'resolveChildRouteBinding'; + + if (! $request->keyable->{$childRouteBindingMethod}( + $parameterName, + $parameter->id, + $route->bindingFieldFor($parameterName) + )) { + throw (new ModelNotFoundException)->setModel(get_class($parameter), [$parameter->id]); + } + + return $next($request); + } + + protected static function getParameterName($name, $parameters) + { + if (array_key_exists($name, $parameters)) { + return $name; + } + + if (array_key_exists($snakedName = Str::snake($name), $parameters)) { + return $snakedName; + } + } +} diff --git a/src/KeyableServiceProvider.php b/src/KeyableServiceProvider.php index 8a753f7..4e74184 100644 --- a/src/KeyableServiceProvider.php +++ b/src/KeyableServiceProvider.php @@ -2,11 +2,14 @@ namespace Givebutter\LaravelKeyable; +use Illuminate\Routing\Route; +use Illuminate\Routing\Router; +use Illuminate\Support\ServiceProvider; +use Illuminate\Routing\PendingResourceRegistration; use Givebutter\LaravelKeyable\Console\Commands\DeleteApiKey; use Givebutter\LaravelKeyable\Console\Commands\GenerateApiKey; use Givebutter\LaravelKeyable\Http\Middleware\AuthenticateApiKey; -use Illuminate\Routing\Router; -use Illuminate\Support\ServiceProvider; +use Givebutter\LaravelKeyable\Http\Middleware\EnforceKeyableScope; class KeyableServiceProvider extends ServiceProvider { @@ -20,12 +23,14 @@ public function boot(Router $router) $this->publishes([ __DIR__ . '/../config/keyable.php' => config_path('keyable.php'), ]); - + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - + $this->registerMiddleware($router); - + $this->registerCommands(); + + $this->registerMacros(); } /** @@ -37,7 +42,7 @@ public function register() { // } - + protected function registerCommands() { if ($this->app->runningInConsole()) { @@ -47,7 +52,7 @@ protected function registerCommands() ]); } } - + /** * Register middleware. * @@ -60,8 +65,25 @@ protected function registerMiddleware(Router $router) $versionComparison = version_compare(app()->version(), '5.4.0'); if ($versionComparison >= 0) { $router->aliasMiddleware('auth.apikey', AuthenticateApiKey::class); + $router->aliasMiddleware('keyableScoped', EnforceKeyableScope::class); } else { $router->middleware('auth.apikey', AuthenticateApiKey::class); + $router->middleware('keyableScoped', EnforceKeyableScope::class); } } + + protected function registerMacros() + { + PendingResourceRegistration::macro('keyableScoped', function () { + $this->middleware('keyableScoped'); + + return $this; + }); + + Route::macro('keyableScoped', function () { + $this->middleware('keyableScoped'); + + return $this; + }); + } } diff --git a/tests/Feature/AuthenticateApiKey.php b/tests/Feature/AuthenticateApiKey.php new file mode 100644 index 0000000..2bb8195 --- /dev/null +++ b/tests/Feature/AuthenticateApiKey.php @@ -0,0 +1,39 @@ +createApiKey(); + + Route::get("/api/posts", function (Request $request) { + return response('All good', 200); + })->middleware(['api', 'auth.apikey']); + + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts")->assertOk(); + } + + /** @test */ + public function request_without_api_key_responds_unauthorized() + { + $account = Account::create(); + $account->createApiKey(); + + Route::get("/api/posts", function (Request $request) { + return response('All good', 200); + })->middleware(['api', 'auth.apikey']); + + $this->get("/api/posts")->assertUnauthorized(); + } +} diff --git a/tests/Feature/EnforceKeyableScope.php b/tests/Feature/EnforceKeyableScope.php new file mode 100644 index 0000000..286c068 --- /dev/null +++ b/tests/Feature/EnforceKeyableScope.php @@ -0,0 +1,57 @@ +createApiKey(); + + $post = $account->posts()->create(); + + Route::get("/api/posts/{post}", function (Request $request, Post $post) { + return response('All good', 200); + })->middleware(['api', 'auth.apikey'])->keyableScoped(); + + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts/{$post->id}")->assertOk(); + } + + /** @test */ + public function request_with_model_not_owned_by_keyable_throws_model_not_found() + { + $account = Account::create(); + $account->createApiKey(); + + $account2 = Account::create(); + $post = $account2->posts()->create(); + + Route::get("/api/posts/{post}", function (Request $request, Post $post) { + return response('All good', 200); + })->middleware([ 'api', 'auth.apikey'])->keyableScoped(); + + try { + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts/{$post->id}"); + } catch (ModelNotFoundException $e) { + $this->assertTrue(true); + return; + } + + // force a fail since it shouldn't reach this point. + $this->assertTrue(false); + } +} diff --git a/tests/Support/Account.php b/tests/Support/Account.php new file mode 100644 index 0000000..f86cfe5 --- /dev/null +++ b/tests/Support/Account.php @@ -0,0 +1,16 @@ +hasMany(Post::class); + } +} diff --git a/tests/Support/Migrations/create_accounts_and_posts_tables.php b/tests/Support/Migrations/create_accounts_and_posts_tables.php new file mode 100644 index 0000000..c78f432 --- /dev/null +++ b/tests/Support/Migrations/create_accounts_and_posts_tables.php @@ -0,0 +1,28 @@ +increments('id'); + $table->timestamps(); + }); + + Schema::create('posts', function (Blueprint $table) { + $table->increments('id'); + $table->foreignId('account_id')->constrained(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('accounts'); + Schema::dropIfExists('posts'); + } +} diff --git a/tests/Support/Post.php b/tests/Support/Post.php new file mode 100644 index 0000000..7ee2846 --- /dev/null +++ b/tests/Support/Post.php @@ -0,0 +1,14 @@ +belongsTo(Account::class); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..187f18f --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,75 @@ +setUpDatabase($this->app); + $this->withoutExceptionHandling(); + } + + protected function getPackageProviders($app) + { + return [ + KeyableServiceProvider::class, + ]; + } + + protected function getEnvironmentSetUp($app) + { + // Setup default database to use sqlite :memory: + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + protected function setUpDatabase($app) + { + $app['db']->connection()->getSchemaBuilder()->create('test_models', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + }); + + $this->prepareDatabaseForHasCustomFieldsModel(); + $this->runMigrationStub(); + } + + protected function runMigrationStub() + { + include_once __DIR__ . '/../database/migrations/2019_04_09_225232_create_api_keys_table.php'; + (new \CreateApiKeysTable())->up(); + } + + protected function prepareDatabaseForHasCustomFieldsModel() + { + include_once __DIR__ . '/../tests/Support/Migrations/create_accounts_and_posts_tables.php'; + (new \CreateAccountsAndPostsTables())->up(); + } + + protected function resetDatabase() + { + $this->artisan('migrate:fresh'); + $this->runMigrationStub(); + } +} From 2dcbcb54e19eda5861fcd00b978c9a577920d829 Mon Sep 17 00:00:00 2001 From: Clint Winter Date: Mon, 10 Jan 2022 11:12:51 -0500 Subject: [PATCH 2/4] improve testing + cleanup --- src/Http/Middleware/EnforceKeyableScope.php | 20 +++------ tests/Feature/EnforceKeyableScope.php | 47 +++++++++++++++++++++ tests/Support/PostsController.php | 14 ++++++ 3 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 tests/Support/PostsController.php diff --git a/src/Http/Middleware/EnforceKeyableScope.php b/src/Http/Middleware/EnforceKeyableScope.php index f4aafaa..1d16ce6 100644 --- a/src/Http/Middleware/EnforceKeyableScope.php +++ b/src/Http/Middleware/EnforceKeyableScope.php @@ -27,20 +27,10 @@ public function handle($request, Closure $next, $guard = null) return $next($request); } - $parameterName = $route->parameterNames()[0]; - $parameter = $route->parameters()[$parameterName]; - - if (! is_object($parameter)) { - $parameter = Arr::first($route->signatureParameters(UrlRoutable::class)); - $instance = app(Reflector::getParameterClassName($parameter)); - - $routeBindingMethod = $route->allowsTrashedBindings() - ? 'resolveSoftDeletableRouteBinding' - : 'resolveRouteBinding'; - - $instance->{$routeBindingMethod}($parameter, $route->bindingFieldFor($parameterName)); - } + $parameterValue = $route->originalParameters()[$parameterName]; + $parameter = Arr::first($route->signatureParameters(UrlRoutable::class)); + $instance = app(Reflector::getParameterClassName($parameter)); $childRouteBindingMethod = $route->allowsTrashedBindings() ? 'resolveSoftDeletableChildRouteBinding' @@ -48,10 +38,10 @@ public function handle($request, Closure $next, $guard = null) if (! $request->keyable->{$childRouteBindingMethod}( $parameterName, - $parameter->id, + $parameterValue, $route->bindingFieldFor($parameterName) )) { - throw (new ModelNotFoundException)->setModel(get_class($parameter), [$parameter->id]); + throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]); } return $next($request); diff --git a/tests/Feature/EnforceKeyableScope.php b/tests/Feature/EnforceKeyableScope.php index 286c068..758c497 100644 --- a/tests/Feature/EnforceKeyableScope.php +++ b/tests/Feature/EnforceKeyableScope.php @@ -6,6 +6,7 @@ use Givebutter\Tests\TestCase; use Givebutter\Tests\Support\Post; use Givebutter\Tests\Support\Account; +use Givebutter\Tests\Support\PostsController; use Illuminate\Support\Facades\Route; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Database\Eloquent\ModelNotFoundException; @@ -54,4 +55,50 @@ public function request_with_model_not_owned_by_keyable_throws_model_not_found() // force a fail since it shouldn't reach this point. $this->assertTrue(false); } + + /** @test */ + public function works_with_resource_routes() + { + // PASSING + $account = Account::create(); + $account->createApiKey(); + + $post = $account->posts()->create(); + + Route::prefix('api')->middleware(['api', 'auth.apikey'])->group(function () { + Route::apiResource('posts', PostsController::class) + ->only('show') + ->keyableScoped(); + }); + + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts/{$post->id}")->assertOk(); + + + // FAILING + $account = Account::create(); + $account->createApiKey(); + + $account2 = Account::create(); + $post = $account2->posts()->create(); + + Route::prefix('api')->middleware(['api', 'auth.apikey'])->group(function () { + Route::apiResource('posts', PostsController::class) + ->only('show') + ->keyableScoped(); + }); + + try { + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts/{$post->id}"); + } catch (ModelNotFoundException $e) { + $this->assertTrue(true); + return; + } + + // force a fail since it shouldn't reach this point. + $this->assertTrue(false); + } } diff --git a/tests/Support/PostsController.php b/tests/Support/PostsController.php new file mode 100644 index 0000000..95f7d91 --- /dev/null +++ b/tests/Support/PostsController.php @@ -0,0 +1,14 @@ + Date: Mon, 10 Jan 2022 15:18:16 -0500 Subject: [PATCH 3/4] Improve tests --- tests/Feature/EnforceKeyableScope.php | 95 +++++++++++-------- tests/Support/Comment.php | 14 +++ tests/Support/CommentsController.php | 14 +++ ...osts_tables.php => create_test_tables.php} | 9 +- tests/Support/Post.php | 6 ++ tests/TestCase.php | 5 +- 6 files changed, 100 insertions(+), 43 deletions(-) create mode 100644 tests/Support/Comment.php create mode 100644 tests/Support/CommentsController.php rename tests/Support/Migrations/{create_accounts_and_posts_tables.php => create_test_tables.php} (69%) diff --git a/tests/Feature/EnforceKeyableScope.php b/tests/Feature/EnforceKeyableScope.php index 758c497..60563c3 100644 --- a/tests/Feature/EnforceKeyableScope.php +++ b/tests/Feature/EnforceKeyableScope.php @@ -6,10 +6,9 @@ use Givebutter\Tests\TestCase; use Givebutter\Tests\Support\Post; use Givebutter\Tests\Support\Account; -use Givebutter\Tests\Support\PostsController; use Illuminate\Support\Facades\Route; -use Illuminate\Auth\Access\AuthorizationException; -use Illuminate\Database\Eloquent\ModelNotFoundException; +use Givebutter\Tests\Support\PostsController; +use Givebutter\Tests\Support\CommentsController; class EnforceKeyableScope extends TestCase { @@ -43,62 +42,80 @@ public function request_with_model_not_owned_by_keyable_throws_model_not_found() return response('All good', 200); })->middleware([ 'api', 'auth.apikey'])->keyableScoped(); - try { - $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, - ])->get("/api/posts/{$post->id}"); - } catch (ModelNotFoundException $e) { - $this->assertTrue(true); - return; - } - - // force a fail since it shouldn't reach this point. - $this->assertTrue(false); + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + ])->get("/api/posts/{$post->id}")->assertNotFound(); } /** @test */ public function works_with_resource_routes() { - // PASSING - $account = Account::create(); - $account->createApiKey(); - - $post = $account->posts()->create(); - Route::prefix('api')->middleware(['api', 'auth.apikey'])->group(function () { Route::apiResource('posts', PostsController::class) ->only('show') ->keyableScoped(); }); + /* + | -------------------------------- + | PASSING + | -------------------------------- + */ + $account = Account::create(); + $post = $account->posts()->create(); + $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, ])->get("/api/posts/{$post->id}")->assertOk(); - - // FAILING - $account = Account::create(); - $account->createApiKey(); - + /* + | -------------------------------- + | FAILING + | -------------------------------- + */ $account2 = Account::create(); $post = $account2->posts()->create(); - Route::prefix('api')->middleware(['api', 'auth.apikey'])->group(function () { - Route::apiResource('posts', PostsController::class) + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, + ])->get("/api/posts/{$post->id}")->assertNotFound(); + } + + /** @test */ + public function can_use_scoped_with_keyableScoped() + { + Route::middleware(['api', 'auth.apikey'])->group(function () { + Route::apiResource('posts.comments', CommentsController::class) ->only('show') + ->scoped() ->keyableScoped(); }); - try { - $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, - ])->get("/api/posts/{$post->id}"); - } catch (ModelNotFoundException $e) { - $this->assertTrue(true); - return; - } - - // force a fail since it shouldn't reach this point. - $this->assertTrue(false); + /* + | -------------------------------- + | PASSING + | -------------------------------- + */ + $account = Account::create(); + $post = $account->posts()->create(); + $comment = $post->comments()->create(); + + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, + ])->get("posts/{$post->id}/comments/{$comment->id}")->assertOk(); + + /* + | -------------------------------- + | FAILING + | -------------------------------- + */ + + $account2 = Account::create(); + $post2 = $account2->posts()->create(); + $comment2 = $post2->comments()->create(); + + $this->withHeaders([ + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, + ])->get("posts/{$post->id}/comments/{$comment2->id}")->assertNotFound(); } } diff --git a/tests/Support/Comment.php b/tests/Support/Comment.php new file mode 100644 index 0000000..c8ef0b1 --- /dev/null +++ b/tests/Support/Comment.php @@ -0,0 +1,14 @@ +belongsTo(Post::class); + } +} diff --git a/tests/Support/CommentsController.php b/tests/Support/CommentsController.php new file mode 100644 index 0000000..71e1ca7 --- /dev/null +++ b/tests/Support/CommentsController.php @@ -0,0 +1,14 @@ +foreignId('account_id')->constrained(); $table->timestamps(); }); + + Schema::create('comments', function (Blueprint $table) { + $table->increments('id'); + $table->foreignId('post_id')->constrained(); + $table->timestamps(); + }); } public function down() { Schema::dropIfExists('accounts'); Schema::dropIfExists('posts'); + Schema::dropIfExists('comments'); } } diff --git a/tests/Support/Post.php b/tests/Support/Post.php index 7ee2846..570b238 100644 --- a/tests/Support/Post.php +++ b/tests/Support/Post.php @@ -3,6 +3,7 @@ namespace Givebutter\Tests\Support; use Givebutter\Tests\Support\Account; +use Givebutter\Tests\Support\Comment; use Illuminate\Database\Eloquent\Model; class Post extends Model @@ -11,4 +12,9 @@ public function account() { return $this->belongsTo(Account::class); } + + public function comments() + { + return $this->hasMany(Comment::class); + } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 187f18f..362017a 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -23,7 +23,6 @@ public function setUp(): void }); $this->setUpDatabase($this->app); - $this->withoutExceptionHandling(); } protected function getPackageProviders($app) @@ -63,8 +62,8 @@ protected function runMigrationStub() protected function prepareDatabaseForHasCustomFieldsModel() { - include_once __DIR__ . '/../tests/Support/Migrations/create_accounts_and_posts_tables.php'; - (new \CreateAccountsAndPostsTables())->up(); + include_once __DIR__ . '/../tests/Support/Migrations/create_test_tables.php'; + (new \CreateTestTables())->up(); } protected function resetDatabase() From d622b757379d282a8d5b2e4111ef397f5084ac62 Mon Sep 17 00:00:00 2001 From: Clint Winter Date: Mon, 10 Jan 2022 15:33:45 -0500 Subject: [PATCH 4/4] More cleanup --- tests/Feature/AuthenticateApiKey.php | 15 +++++---------- tests/Feature/EnforceKeyableScope.php | 23 +++++++++-------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/tests/Feature/AuthenticateApiKey.php b/tests/Feature/AuthenticateApiKey.php index 2bb8195..61f7e51 100644 --- a/tests/Feature/AuthenticateApiKey.php +++ b/tests/Feature/AuthenticateApiKey.php @@ -2,7 +2,6 @@ namespace Givebutter\Tests\Feature; -use Illuminate\Http\Request; use Givebutter\Tests\TestCase; use Givebutter\Tests\Support\Account; use Illuminate\Support\Facades\Route; @@ -12,25 +11,21 @@ class AuthenticateApiKey extends TestCase /** @test */ public function request_with_api_key_responds_ok() { - $account = Account::create(); - $account->createApiKey(); - - Route::get("/api/posts", function (Request $request) { + Route::get("/api/posts", function () { return response('All good', 200); })->middleware(['api', 'auth.apikey']); + $account = Account::create(); + $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, ])->get("/api/posts")->assertOk(); } /** @test */ public function request_without_api_key_responds_unauthorized() { - $account = Account::create(); - $account->createApiKey(); - - Route::get("/api/posts", function (Request $request) { + Route::get("/api/posts", function () { return response('All good', 200); })->middleware(['api', 'auth.apikey']); diff --git a/tests/Feature/EnforceKeyableScope.php b/tests/Feature/EnforceKeyableScope.php index 60563c3..1f33d37 100644 --- a/tests/Feature/EnforceKeyableScope.php +++ b/tests/Feature/EnforceKeyableScope.php @@ -15,35 +15,31 @@ class EnforceKeyableScope extends TestCase /** @test */ public function request_with_parameter_must_be_owned_by_keyable() { - $account = Account::create(); - $account->createApiKey(); - - $post = $account->posts()->create(); - Route::get("/api/posts/{post}", function (Request $request, Post $post) { return response('All good', 200); })->middleware(['api', 'auth.apikey'])->keyableScoped(); + $account = Account::create(); + $post = $account->posts()->create(); + $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, ])->get("/api/posts/{$post->id}")->assertOk(); } /** @test */ public function request_with_model_not_owned_by_keyable_throws_model_not_found() { - $account = Account::create(); - $account->createApiKey(); - - $account2 = Account::create(); - $post = $account2->posts()->create(); - Route::get("/api/posts/{post}", function (Request $request, Post $post) { return response('All good', 200); })->middleware([ 'api', 'auth.apikey'])->keyableScoped(); + $account = Account::create(); + $account2 = Account::create(); + $post = $account2->posts()->create(); + $this->withHeaders([ - 'Authorization' => 'Bearer ' . $account->apiKeys()->first()->key, + 'Authorization' => 'Bearer ' . $account->createApiKey()->key, ])->get("/api/posts/{$post->id}")->assertNotFound(); } @@ -109,7 +105,6 @@ public function can_use_scoped_with_keyableScoped() | FAILING | -------------------------------- */ - $account2 = Account::create(); $post2 = $account2->posts()->create(); $comment2 = $post2->comments()->create();