I have a single page application which is computing multiple AJAX requests, via axios
. Occasionally, I run into a scenario where both requests run async at the same time and attempt to write to the session which causes a 419
response code where the CSRF
token is dropped in the response forcing me to have to logout the user.
After debugging this, I come across session blocking which makes use of atomic locks.
My session provider is the database and I have the standard Schema that ships with Laravel for this capability. Currently, I must specify this on my routes like so:
Route::any('/example', [SomeController::class, 'someFunction')->block();
However, I have a mass amount of routes and since the application is SPA, is there a way to make this happen by default at service provider level?
It is not possible to Route::group(...)->block()
which is what I did originally try.
CodePudding user response:
Achieving this is a bit of a pain. But before I present a solution, a short analysis:
The Route::block($lockSeconds = 10, $waitSeconds = 10)
method internally sets the attributes lockSeconds
and waitSeconds
on the Route. If these two attributes are added to a group definition, they are actually passed to the route, but unfortunately under the sub key action
:
Route::group(['lockSeconds' => 10, 'waitSeconds' => 10, 'prefix' => 'api/spa'], function () {
Route::get('foo', fn () => response()->json(['result' => 'ok']));
});
// Dump of the route
"api/spa/foo" => Illuminate\Routing\Route {#217 ▼
uri: "api/spa/foo"
methods: array:2 [▶]
action: array:5 [▼
"middleware" => array:1 [▶]
"uses" => Closure() {#216 ▶}
"namespace" => null
"prefix" => ""
"where" => [],
"lockSeconds" => 10, <-- we got the setting here
"waitSeconds" => 10 <--
]
isFallback: false
controller: null
defaults: []
wheres: []
parameters: null
parameterNames: null
#originalParameters: null
#withTrashedBindings: false
#lockSeconds: null <-- we want the setting here though
#waitSeconds: null <--
computedMiddleware: null
compiled: null
#router: Illuminate\Routing\Router {#25 ▶}
#container: Illuminate\Foundation\Application {#3 ▶}
#bindingFields: []
}
That leaves us with the situation that defining the two attributes during route registration is not possible. But fortunately, we can also manipulate routes after they've been added to the route collection:
foreach (Route::getRoutes() as $route) {
$route->block();
}
This code is best placed at the bottom of your routes/web.php
or at the end of the map()
method in your RouteServiceProvider
. You also may want to filter your routes when doing this and only update routes starting with a given prefix:
foreach (Route::getRoutes() as $route) {
if (str_starts_with($route->uri(), 'api/spa')) {
$route->block();
}
}