From a8c45cdbc30bec139d1765fa61dcc532330bb63e Mon Sep 17 00:00:00 2001 From: Wire Date: Sat, 7 Dec 2024 23:01:28 +0000 Subject: [PATCH] auth fixes --- app/Http/Kernel.php | 14 +---- app/Http/Middleware/ApiAuthenticate.php | 51 ------------------- app/Http/Middleware/CanAccessAdminRoutes.php | 4 +- app/Http/Middleware/EnsureUserIsAdmin.php | 3 +- app/Http/Middleware/EnsureUserIsGameAdmin.php | 3 +- app/Http/Middleware/Throttle.php | 3 +- app/Policies/TestPolicy.php | 5 +- app/Providers/AppServiceProvider.php | 30 ++++++----- app/Providers/AuthServiceProvider.php | 2 +- app/Providers/RouteServiceProvider.php | 2 +- app/Services/Auth/ApiSanctumGuard.php | 38 ++++++++++++++ config/auth.php | 4 ++ config/scramble.php | 2 +- 13 files changed, 74 insertions(+), 87 deletions(-) delete mode 100644 app/Http/Middleware/ApiAuthenticate.php create mode 100644 app/Services/Auth/ApiSanctumGuard.php diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index f9d9758..578669d 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -2,9 +2,7 @@ namespace App\Http; -use Illuminate\Foundation\Application; use Illuminate\Foundation\Http\Kernel as HttpKernel; -use Illuminate\Routing\Router; class Kernel extends HttpKernel { @@ -43,9 +41,8 @@ class Kernel extends HttpKernel ], 'api' => [ - // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, - \App\Http\Middleware\ApiAuthenticate::class, \App\Http\Middleware\Throttle::class, ], ]; @@ -58,7 +55,6 @@ class Kernel extends HttpKernel * @var array */ protected $middlewareAliases = [ - 'apiauth' => \App\Http\Middleware\ApiAuthenticate::class, 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, @@ -71,12 +67,4 @@ class Kernel extends HttpKernel 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ]; - - public function __construct(Application $app, Router $router) - { - // Our custom throttle middleware relies on user auth being done first - array_push($this->middlewarePriority, \App\Http\Middleware\Throttle::class); - - parent::__construct($app, $router); - } } diff --git a/app/Http/Middleware/ApiAuthenticate.php b/app/Http/Middleware/ApiAuthenticate.php deleted file mode 100644 index 1e2ae42..0000000 --- a/app/Http/Middleware/ApiAuthenticate.php +++ /dev/null @@ -1,51 +0,0 @@ -bearerToken(); - if ($bearer) { - $pat = null; - if (str_contains($bearer, '|')) { - $tokenParts = explode('|', $bearer, 2); - if (count($tokenParts) === 2) { - $id = $tokenParts[0]; - $token = $tokenParts[1]; - $pat = PersonalAccessToken::find($id); - if (hash('sha256', $token) !== $pat->token) { - $pat = null; - } - } - } else { - $pat = PersonalAccessToken::where('token', hash('sha256', $bearer)) - ->first(); - } - - if ($pat) { - if ($user = User::find($pat->tokenable_id)) { - $request->setUserResolver(function () use ($user) { - return $user; - }); - - return $next($request); - } - } - } - - return response()->json(['message' => 'Unauthenticated.'], 401); - } -} diff --git a/app/Http/Middleware/CanAccessAdminRoutes.php b/app/Http/Middleware/CanAccessAdminRoutes.php index 7759d10..ba19c61 100644 --- a/app/Http/Middleware/CanAccessAdminRoutes.php +++ b/app/Http/Middleware/CanAccessAdminRoutes.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\URL; @@ -17,7 +18,8 @@ class CanAccessAdminRoutes */ public function handle(Request $request, Closure $next) { - if (! $request->user()->isAdmin() && ! $request->user()->isGameAdmin()) { + $user = Auth::user(); + if (! $user->isAdmin() && ! $user->isGameAdmin()) { return $request->expectsJson() ? abort(403, 'You don\'t have permission to access this route.') : Redirect::guest(URL::route('dashboard')); diff --git a/app/Http/Middleware/EnsureUserIsAdmin.php b/app/Http/Middleware/EnsureUserIsAdmin.php index f41ff9f..5537c32 100644 --- a/app/Http/Middleware/EnsureUserIsAdmin.php +++ b/app/Http/Middleware/EnsureUserIsAdmin.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\URL; @@ -17,7 +18,7 @@ class EnsureUserIsAdmin */ public function handle(Request $request, Closure $next) { - if (! $request->user()?->isAdmin()) { + if (! Auth::user()?->isAdmin()) { return $request->expectsJson() ? abort(403, 'You don\'t have permission to access this route.') : Redirect::guest(URL::route('dashboard')); diff --git a/app/Http/Middleware/EnsureUserIsGameAdmin.php b/app/Http/Middleware/EnsureUserIsGameAdmin.php index dec0ec3..1a6de0f 100644 --- a/app/Http/Middleware/EnsureUserIsGameAdmin.php +++ b/app/Http/Middleware/EnsureUserIsGameAdmin.php @@ -4,6 +4,7 @@ use Closure; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\URL; @@ -17,7 +18,7 @@ class EnsureUserIsGameAdmin */ public function handle(Request $request, Closure $next) { - if (! $request->user()->isGameAdmin()) { + if (! Auth::user()->isGameAdmin()) { return $request->expectsJson() ? abort(403, 'You don\'t have permission to access this route.') : Redirect::guest(URL::route('dashboard')); diff --git a/app/Http/Middleware/Throttle.php b/app/Http/Middleware/Throttle.php index 35844e7..13afdeb 100644 --- a/app/Http/Middleware/Throttle.php +++ b/app/Http/Middleware/Throttle.php @@ -4,12 +4,13 @@ use Closure; use Illuminate\Routing\Middleware\ThrottleRequests; +use Illuminate\Support\Facades\Auth; class Throttle extends ThrottleRequests { public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $prefix = '') { - if ($request->user()?->isAdmin()) { + if (Auth::user()?->isAdmin()) { return $next($request); } diff --git a/app/Policies/TestPolicy.php b/app/Policies/TestPolicy.php index 548bb9c..a25617d 100644 --- a/app/Policies/TestPolicy.php +++ b/app/Policies/TestPolicy.php @@ -9,10 +9,7 @@ class TestPolicy /** * Create a new policy instance. */ - public function __construct() - { - // - } + public function __construct() {} public function view(User $user): bool { diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 45e23e4..4e35fb2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,13 +3,13 @@ namespace App\Providers; use App\Models\PersonalAccessToken; +use App\Services\Auth\ApiSanctumGuard; use Dedoc\Scramble\Scramble; use Dedoc\Scramble\Support\Generator\OpenApi; use Dedoc\Scramble\Support\Generator\SecurityScheme; -use Illuminate\Auth\Access\Gate as AccessGate; -use Illuminate\Contracts\Auth\Access\Gate as GateContract; -use Illuminate\Foundation\Application; +use Illuminate\Auth\RequestGuard; use Illuminate\Routing\Route; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Blade; use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; @@ -24,8 +24,6 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - $this->registerAccessGate(); - if ($this->app->environment(['local', 'staging'])) { $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); $this->app->register(TelescopeServiceProvider::class); @@ -43,6 +41,14 @@ public function boot() Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class); + Auth::resolved(function ($auth) { + $auth->extend('api', function ($app, $name, array $config) use ($auth) { + return tap($this->createApiGuard($auth, $config), function ($guard) { + app()->refresh('request', $guard, 'setRequest'); + }); + }); + }); + Scramble::extendOpenApi(function (OpenApi $openApi) { $openApi->secure( SecurityScheme::http('bearer', 'JWT') @@ -50,7 +56,7 @@ public function boot() }); Scramble::routes(function (Route $route) { - return $route->getDomain() === config('app.api_url'); + return $route->getDomain() === preg_replace('(^https?://)', '', config('app.api_url')); }); Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) { @@ -69,12 +75,12 @@ protected function loadHelpers() } } - protected function registerAccessGate() + protected function createApiGuard($auth, $config) { - $this->app->scoped(GateContract::class, function (Application $app) { - return new AccessGate($app, function () { - return request()->user(); - }); - }); + return new RequestGuard( + new ApiSanctumGuard($auth, config('sanctum.expiration'), $config['provider']), + request(), + $auth->createUserProvider($config['provider'] ?? null) + ); } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index a714b57..e340490 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -25,7 +25,7 @@ class AuthServiceProvider extends ServiceProvider */ public function boot(): void { - Gate::before(function (User $user, string $ability) { + Gate::before(function (User $user) { if ($user->isAdmin()) { // Admins can do anything return true; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 18e5606..c1b4b66 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -28,7 +28,7 @@ public function boot() } $this->routes(function () { - Route::middleware('api') + Route::middleware(['auth:api', 'api']) ->domain(config('app.api_url')) ->group(base_path('routes/api.php')); diff --git a/app/Services/Auth/ApiSanctumGuard.php b/app/Services/Auth/ApiSanctumGuard.php new file mode 100644 index 0000000..f04300f --- /dev/null +++ b/app/Services/Auth/ApiSanctumGuard.php @@ -0,0 +1,38 @@ +getTokenFromRequest($request)) { + $model = Sanctum::$personalAccessTokenModel; + + $accessToken = $model::findToken($token); + + if (! $this->isValidAccessToken($accessToken) || + ! $this->supportsTokens($accessToken->tokenable)) { + return; + } + + $tokenable = $accessToken->tokenable->withAccessToken( + $accessToken + ); + + event(new TokenAuthenticated($accessToken)); + + return $tokenable; + } + } +} diff --git a/config/auth.php b/config/auth.php index d8c6cee..0124e46 100644 --- a/config/auth.php +++ b/config/auth.php @@ -40,6 +40,10 @@ 'driver' => 'session', 'provider' => 'users', ], + 'api' => [ + 'driver' => 'api', + 'provider' => 'users', + ] ], /* diff --git a/config/scramble.php b/config/scramble.php index c28a206..7bf39f3 100644 --- a/config/scramble.php +++ b/config/scramble.php @@ -13,7 +13,7 @@ * Your API domain. By default, app domain is used. This is also a part of the default API routes * matcher, so when implementing your own, make sure you use this config if needed. */ - 'api_domain' => config('app.api_url'), + 'api_domain' => preg_replace('(^https?://)', '', config('app.api_url')), 'info' => [ /*