Laravel 10:中间件中Session重生成后值未更新的问题
Laravel 10会话更新异常问题排查
场景描述
我正在开发一个Laravel 10应用,使用中间件检查外部API的token是否过期。若token过期,将通过refresh_token生成新token,更新会话中的相关数据(token、refresh_token、expires_at)。
中间件代码
namespace App\Http\Middleware; use Closure; use Carbon\Carbon; use Nanicas\Auth\Services\ThirdPartyAuthService; use Illuminate\Support\Facades\Auth; use Illuminate\Http\Request; class NanicasAuthenticateMiddleware { public function handle(Request $request, Closure $next) { $auth = $request->session()->get('nanicas'); if (empty($auth)) { return $this->logout($request); } if (!Carbon::now()->greaterThanOrEqualTo($auth['expires_at_datetime'])) { return $next($request); } $config = config('nanicas'); $authService = app()->make(ThirdPartyAuthService::class); $authResponse = $authService->refreshToken([ 'grant_type' => 'refresh_token', 'client_id' => $config['CLIENT_ID'], 'client_secret' => $config['CLIENT_SECRET'], 'refresh_token' => $auth['refresh_token'], 'scope' => '', ]); if (!$authResponse['status']) { return $this->logout($request); } $request->session()->regenerate(); $request->session()->put('nanicas', $authResponse['body']); return $next($request); } private function logout(Request $request) { $request->session()->forget('nanicas'); Auth::logout(); $request->session()->invalidate(); return $request->expectsJson() ? response()->json(['message' => 'Token expirado'], 401) : redirect()->route('login'); } }
路由配置
Route::middleware('auth.nanicas')->group(function () { Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); });
问题核心
Laravel会话有效期为2天,但外部API的token每2小时过期一次。当token过期后刷新HOME页面,会话仍保留旧值——仅在使用$request->session()->regenerate()时出现此问题,移除该代码后一切正常。
疑问:
- 为何使用
regenerate()时会话未更新为新值? - 注释掉web组中的
\App\Http\Middleware\EncryptCookies::class中间件会生成一些随机ID,这是否与该问题相关?
问题解答
1. regenerate()导致会话数据不更新的原因
你当前的代码执行顺序错误:先调用regenerate()再更新会话数据。Laravel的regenerate()方法会执行以下操作:
- 创建新的会话ID
- 将当前会话的所有数据复制到新会话
- 销毁旧会话
这意味着你在regenerate()之后调用put()写入的新数据,仅存在于当前请求的临时会话实例中,但新会话的Cookie还未发送给浏览器。下一次请求时,浏览器仍携带旧会话ID,读取到的自然还是旧数据。
修正方案:调整执行顺序,先更新会话数据,再重新生成会话ID:
// 先写入新的token数据 $request->session()->put('nanicas', $authResponse['body']); // 再重新生成会话ID,此时新数据会被复制到新会话中 $request->session()->regenerate();
2. 关于EncryptCookies中间件的疑问
注释掉EncryptCookies后出现的随机ID,是Laravel为未加密的会话Cookie自动添加的签名(用于验证数据未被篡改),这和你当前的会话数据不更新问题没有直接关联。但强烈建议不要禁用该中间件——它是Laravel会话安全的核心保障,禁用后会话数据会以明文形式存储在Cookie中,极易被篡改或窃取。
额外优化建议
- 使用
regenerate(true)替代regenerate(),该方法会立即使旧会话失效,进一步防范会话固定攻击。 - 为第三方API的refreshToken请求添加异常捕获逻辑,避免API请求失败导致页面崩溃。
内容的提问来源于stack exchange,提问作者José Victor
相关产品推荐
相关产品推荐

