使用过程中,发现登录过期,没有进行跳转,求如何统一处理登录过期跳转
分享
收藏
评论
作者 🐼
w念
-

修改login中间件也不行
这个问题在 PHP 项目中非常典型。**“登录过期不跳转”** 的本质原因是:中间件没有正确拦截非正常请求,或者前后端架构对 `401/403` 状态的响应预期不一致。
由于你提到使用的是类似 EasyAdmin 的项目栈(通常基于 Laravel + Vue/Blade),下面提供一套**生产环境可直接落地的统一处理方案**。
---
### 🔍 为什么修改 `login` 中间件无效?
- `login` 中间件通常只作用于 `/login` 等认证相关路由,**不会拦截业务路由**。
- 登录过期后,访问的是 `/dashboard`、`/api/data` 等业务路径,若这些路由未挂载正确的认证中间件,或中间件判断逻辑不匹配当前请求类型,就会静默失败或直接暴露空白页/旧会话。
---
### ✅ 统一处理方案(以 Laravel 为例)
#### 1️⃣ 创建全局认证过期处理中间件
```bash
php artisan make:middleware HandleAuthExpired
```
**`app/Http/Middleware/HandleAuthExpired.php`**
```php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\Auth;
class HandleAuthExpired
{
public function handle(Request $request, Closure $next): Response
{
// 如果不是安全状态且未认证,说明会话过期或从未登录
if (!$request->user() && !Auth::check()) {
// 区分 Web 页面请求 与 API/AJAX 请求
if ($request->expectsJson()) {
// API/JS 请求:返回标准 401 JSON,由前端统一拦截跳转
return response()->json([
'code' => 401,
'message' => '登录已过期,请重新登录',
'path' => route('login') // 可选:提供跳转地址
], 401);
} else {
// 传统页面请求:带来源路径重定向到登录页
return redirect()->guest(route('login'))->withInput($request->except('_token'));
}
}
return $next($request);
}
}
```
#### 2️⃣ 注册中间件并绑定到路由组
编辑 `app/Http/Kernel.php`,将中间件加入全局组或特定路由组:
```php
protected $routeMiddleware = [
// ... 其他中间件
'auth.expired' => \App\Http\Middleware\HandleAuthExpired::class,
];
protected $middlewareGroups = [
'web' => [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
// ... 其他 web 中间件
// 注意:不要在这里重复加 'auth',否则会导致双重拦截冲突
\App\Http\Middleware\HandleAuthExpired::class, // 加入 web 组底部
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
// \Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\HandleAuthExpired::class, // 加入 api 组底部
],
];
```
#### 3️⃣ 路由声明规范(关键!)
确保你的业务路由使用了正确的中间件组:
```php
// routes/web.php 示例
Route::middleware(['web'])->group(function () {
Route::get('/', function () { return view('welcome'); });
Route::resource('articles', ArticleController::class);
});
// routes/api.php 示例(自动挂载 api 组)
Route::get('/test', function () { return ['status' => 'ok']; });
```
> 💡 **注意**:不要在单个路由上混写 `'auth'` 和 `HandleAuthExpired`,一个即可。
---
### 🌐 前后端分离场景补充(强烈推荐)
如果你的项目是 **Laravel API + Vue/React 前端**,服务端**只负责返回 `401`**,跳转必须由前端完成:
**前端 Axios 拦截器示例:**
```javascript
axios.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
localStorage.clear();
// 统一跳转到登录页,保留当前 URL 以便登录后回跳
const currentPath = window.location.pathname + window.location.search;
window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`;
}
return Promise.reject(error);
}
);
```
---
### 🛠 排查清单(如果仍不生效)
| 现象 | 可能原因 | 解决方式 |
|------|----------|----------|
| 刷新页面仍停留在当前页 | 浏览器缓存了旧 HTML/JS | 清除缓存或使用 `Ctrl+F5` |
| 控制台报 `CORS` 或 `mixed content` | 跨域或未设置 `SANCTUM_STATEFUL_DOMAINS` | 检查 `.env` 及 `config/cors.php` |
| 只有部分路由不跳转 | 路由未挂载 `web`/`api` 中间件组 | 检查 `RouteServiceProvider` 或路由前缀 |
| 登录后仍提示过期 | `SESSION_LIFETIME` 设置过短或 Redis/文件驱动异常 | 查看 `storage/logs/laravel.log` |
---
如果你能补充以下信息,我可以给出更精确的代码适配:
1. 基础框架版本(如 Laravel 9/10/11?)
2. 当前路由结构(传统 Blade 渲染 / 前后端分离 / 混合模式?)
3. 登录过期时浏览器 Network 面板返回的状态码和响应头是什么?
提供后我可为你生成一键替换的代码包。