Laravel 5.5 API中间件:如何识别AJAX请求并验证CSRF而非API凭证?
Great question! When building a hybrid Laravel 5.5 app that serves both API clients and AJAX-powered UI requests, you can customize your API authentication middleware to detect AJAX calls and switch validation logic seamlessly. Here's a practical, Laravel-native approach to pull this off:
Instead of modifying Laravel's core middleware, build a custom one that handles both API credential checks and AJAX CSRF validation. This keeps your logic clean and maintainable.
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Auth\AuthenticationException; use Illuminate\Http\Request; class AuthenticateApiOrAjax { public function handle(Request $request, Closure $next) { // Detect AJAX requests using Laravel's built-in method if ($request->ajax()) { // Let Laravel's default CSRF middleware handle validation // Make sure the CSRF middleware is active in your web middleware group return $next($request); } // For non-AJAX API requests, enforce standard API authentication // Adjust this to match your API auth method (Passport, token-based, etc.) if (! $request->user()) { throw new AuthenticationException( 'Unauthenticated.', [], route('login') // Redirect UI users, return JSON for API clients automatically ); } return $next($request); } }
Add your custom middleware to the route middleware list in app/Http/Kernel.php:
protected $routeMiddleware = [ // ... existing middleware entries 'auth.hybrid' => \App\Http\Middleware\AuthenticateApiOrAjax::class, ];
Group the routes that need to accept both API and AJAX requests with your new middleware:
// Routes that support both API credentials and AJAX CSRF validation Route::group(['middleware' => 'auth.hybrid'], function () { Route::get('/api/user/profile', 'UserController@showProfile'); Route::post('/api/user/profile', 'UserController@updateProfile'); Route::delete('/api/user/items/{id}', 'ItemController@destroy'); // Add more hybrid routes here });
For AJAX calls to work, you need to include the CSRF token in your requests. First, add the token to your layout's meta tags:
<meta name="csrf-token" content="{{ csrf_token() }}">
Then, configure your JavaScript to send the token automatically (example with jQuery):
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
If you need stricter differentiation between API and AJAX requests, check for JSON acceptance headers to confirm API requests:
public function handle(Request $request, Closure $next) { // Check if the request explicitly expects JSON (likely an API client) if ($request->wantsJson() && !$request->ajax()) { // Enforce API authentication if (! $request->user()) { throw new AuthenticationException('Unauthenticated.'); } } else { // AJAX or regular web request, rely on CSRF protection return $next($request); } return $next($request); }
This approach keeps your authentication logic centralized while supporting both your API clients and UI-driven AJAX requests smoothly.
内容的提问来源于stack exchange,提问作者Joshua Wieczorek

