Laravel 8 Sanctum鉴权遇503错误:跨域Postman调用失败求助
我在Laravel 8中配置好了Sanctum,数据库里也能生成personal_access_tokens,但用Postman携带Bearer Token调用API时一直返回503 Service Unavailable。已经确认服务器不在维护模式(执行过php artisan up),因为是跨设备调用(Postman测试,后续是Windows设备向网站传数据),怀疑是stateful配置的问题,卡了4天没解决。
相关配置代码
api.php
<?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\V2\Api\KeywordsController; Route::middleware(['auth:sanctum', 'abilities:db:view,db:update,db:store'])->group(function () { Route::get('fetch-keyword', [KeywordsController::class, 'fetchKeyword']); Route::put('update-keyword/{keywordName}', [KeywordsController::class, 'updateKeyword']); });
auth.php
<?php return [ 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'sanctum', 'provider' => 'users', 'hash' => false, ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], ], 'verification' => [ 'expire' => 1440, ], 'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_resets', 'expire' => 180, 'throttle' => 60, ], ], 'password_timeout' => 10800, ];
sanctum.php
<?php use Laravel\Sanctum\Sanctum; return [ 'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', Sanctum::currentApplicationUrlWithPort() ))), 'guard' => ['api'], 'expiration' => null, 'middleware' => [ 'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class, 'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class, ], ];
User模型
<?php namespace App\Models; use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Paddle\Billable; use Spatie\Permission\Traits\HasRoles; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable implements MustVerifyEmail { use HasApiTokens, HasFactory, Notifiable, Billable, HasRoles; .....more code not attached
Kernel.php
<?php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]; protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class, 'abilities' => \Laravel\Sanctum\Http\Middleware\CheckAbilities::class, 'ability' => \Laravel\Sanctum\Http\Middleware\CheckForAnyAbility::class, ]; }
Token生成逻辑
public function update(Request $request, $id) { $validator = Validator::make($request->all(), [ 'name' => 'required|string|max:255', 'email' => ['required', Rule::unique('users')->ignore($id)], 'has_token' => 'nullable|boolean', 'password' => $request->filled('password') ? 'required|min:8' : '', 'token_name' => [ 'nullable', 'string', Rule::requiredIf(function () use ($request) { return $request->has_token === 1; }), ], ]); if ($validator->fails()) { return response()->json(['errors' => $validator->errors()], 422); } try { $user = User::find($id); if ($request->email !== $user->email) { return $this->changeEmail($request->email, $request->password, $id); } // Update fields $user->name = $request->name; $user->current_credits = $request->current_credits; if ($request->filled('password')) { $user->password = Hash::make($request->password); } $user->save(); $user = User::where('email', $request->email)->first(); if ($request->has_token === 1 && $request->filled('token_name')) { $user->createToken($request->token_name, ['db:view', 'db:update', 'db:store']); } elseif ($request->has_token === 0) { $user->tokens()->delete(); } } catch (Exception $e) { return response()->json(['error' => $e->getMessage()], 500); } return response()->json(['success' => 'success'], 200); }
排查建议
- 查看服务器日志:503属于服务器层面错误,优先检查Nginx/Apache的错误日志,以及Laravel
storage/logs目录下的日志,定位具体报错原因。 - 调整Sanctum Stateful配置:跨设备调用不属于stateful场景,在
.env中设置SANCTUM_STATEFUL_DOMAINS=为空,同时确保SESSION_DOMAIN配置正确(本地测试可设为localhost或空)。 - 修正API中间件:当前
api中间件组中ThrottleRequests重复,删除throttle:60,1,保留\Illuminate\Routing\Middleware\ThrottleRequests::class.':api'避免冲突。 - 验证Token格式与权限:确认Postman请求头
Authorization格式为Bearer {token},且该Token关联用户拥有db:view,db:update,db:store权限。 - 测试基础路由:创建一个不带
auth:sanctum和abilities的测试API,验证服务器是否能正常响应,排除路由或服务器基础配置问题。 - 清除缓存:执行
php artisan config:clear、php artisan cache:clear、php artisan route:clear确保配置生效。
内容的提问来源于stack exchange,提问作者Benny
相关产品推荐
相关产品推荐

