1. Laravel中间件是什么?
在 Laravel中,中间件是控制HTTP请求的一种机制。它提供了一种方便的方式来过滤进入应用程序的请求并对其进行修改。中间件可以为所有请求添加功能,例如:身份验证、与数据处理相关的更改或其他的一些操作。每个中间件都继承了Illuminate\Contracts\Middleware中间件契约,并实现了handle方法。
在Laravel应用中,可以通过中间件完成下面的一些操作:
对请求进行身份验证,以确保其具有授权访问应用程序所需的权限。
确保请求中包含足够的数据。
了解哪些用户正在使用应用程序并记录相关信息。
让我们来看一下Laravel应用程序中的中间件是如何组合的。
2. 中间件的组合
Laravel中的中间件可以单独使用,也可以组合使用。在中间件组合的情况下,每个中间件都可以执行一些操作并且转发到下一个中间件。您可以在应用程序的HTTP内核中定义您需要的中间件组,这样就可以对您的应用程序的所有请求进行处理。HTTP内核在Laravel框架的app/http内核目录中“Kernel”类中定义。
Laravel还提供了全局中间件,这些中间件将被应用程序的所有请求使用。Laravel还提供了路由中间件,这些中间件将仅被与特定路由关联的请求使用。
让我们先看一下如何定义Laravel应用程序的HTTP内核以及如何将中间件组添加到这个内核中。
3. 定义中间件组
Laravel应用程序的HTTP内核是Web应用程序的入口点。一个HTTP内核包含了应用程序处理请求需要所有中间件组。HTTP内核中定义的每个中间件组都会有一个名字,以便在应用程序的其他地方引用。在HTTP内核中定义中间件组需要使用middlewareGroups属性。下面是一个包括两个中间件组的例子:
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
上面的例子中web是一个中间件组,它包含了三个中间件(中间件的名称分别是Illuminate\Session\Middleware\StartSession、Illuminate\View\Middleware\ShareErrorsFromSession和App\Http\Middleware\VerifyCsrfToken)。另外一个中间件组叫做api,它包含了throttle和SubstituteBindings中间件。
3.1 全局中间件
全局中间件的作用是当一个应用程序的每个请求到达应用程序时,都会运行这些中间件。这些中间件是使用middleware属性注册的。全局中间件的例子:
// app/Http/Kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
在上面的代码中,应用程序使用了四个全局中间件,分别是Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode、Illuminate\Foundation\Http\Middleware\ValidatePostSize、App\Http\Middleware\TrimStrings、Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull。
下面让我们来看看Laravel自带的一些中间件是如何工作的。
4. Laravel中预定义的中间件
Laravel框架内置了许多中间件。在HTTP内核中有一些中间件组是默认预定义的,它们可以在应用程序的HTTP内核的$middlewareGroups属性中找到。这些预定义的中间件组是:
'web' => [
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
在上面的例子中,web和api两个中间件组在session、view、csrf和bindings中间件中组合。下面我们将分别介绍上面列出的每个中间件。
4.1 StartSession 中间件
StartSession 中间件会检查每个请求的会话。如果检测到尚未启动会话,它将启动会话。下面的代码片段演示了StartSession如何在HTTP内核中使用:
// start session in Kernel.php
class Kernel extends HttpKernel {
protected $middlewareGroups = [ //...
'web' => [
\Illuminate\Session\Middleware\StartSession::class,
//...
],
//...
];
}
这个中间件在安全方面很重要,因为它确保会话已启动并且使用安全的配置。会话是任何Laravel应用程序核心的一部分。大多数应用程序都需要确定哪些用户正在使用应用程序。
4.2 ShareErrorsFromSession 中间件
在执行此中间件时,Laravel会查看是否存在有会话错误,并将其添加到当前请求中的变量errors中。这个变量可以像在下面这个例子中那样在Laravel中的Blade模板
中使用:
<!-- in login.blade.php -->
<h1>Log in</h1>
<form action="/login" method="POST">
<input name="_token" value="token_value_here" type="hidden">
</form>
@if($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
这个中间件的作用是在初始引导过程中将会话中的错误消息共享到视图中。
4.3 VerifyCsrfToken 中间件
当在Laravel应用程序中进行Web表单提交时(例如提交用户登录表单),默认情况下需要包括CSRF Token
。这个Token是一种安全的方式,用于防止非法提交。VerifyCsrfToken 中间件用于验证此令牌是否包含在请求中,以确保所有的表单提交都是有效的和想要的。如果没有包含CSRF令牌,则会引发TokenMismatchException
异常。
4.4 SubstituteBindings 中间件
SubstituteBindings 中间件确保路由模型绑定不使用类似 id 的字段依靠。此外,它确保通过依赖项注入的控制器不能使用这些选项的任何组合。以下是如何在内核文件中使用这个中间件:
// app/Http/Kernel.php
class Kernel extends HttpKernel {
protected $middlewareGroups = [ //...
'web' => [
\Illuminate\Routing\Middleware\SubstituteBindings::class,
//...
],
//...
];
}
根据上面的代码,我们可以看出这个中间件确保路由模型绑定工作正常,还实现了基于依赖项注入机制的自动依赖项方法注入。
5. 编写自己的中间件
我们在前面介绍了预定义的中间件。除此之外,你还可以编写自己的自定义中间件。让我们来创建一个自定义的用户身份验证中间件。我们要实现的中间件是:
如果一个用户尚未通过身份验证或者他们目前尚未被授权,将他们重定向到登录页面。
如果用户已被授权并且已经通过了身份验证,则执行下一个中间件。
下面是我们要实现的示例用户身份验证中间件的代码:
<?php
namespace App\Http\Middleware;
use Closure;
class Authenticate {
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next) {
if ($request->user() == null) {
return redirect('/login');
}
return $next($request);
}
}
上述中间件在其handle方法中获取HTTP请求并检查用户是否通过身份验证。如果用户未通过身份验证,则重定向到定义的登录URL中。否则,请求将继续执行。
下一步是将我们的中间件添加到HTTP内核中,以便于使用。我们只需要将其添加到HTTP内核中的web中间件组,或者我们也可以在需要此中间件的路由上使用中间件进行指定。下面是将中间件添加到HTTP内核中的方法:
// app/Http/Kernel.php
class Kernel extends HttpKernel {
protected $routeMiddleware = [ //...
'auth' => \App\Http\Middleware\Authenticate::class,
//...
];
}
上面的代码会将我们的Authenticate中间件添加到HTTP内核中的路由中,且该中间件的别名为auth。然后我们可以使用这个别名在路由中指定这个中间件,如下所示:
Route::middleware(['auth'])->group(function () {
Route::get('/home', 'HomeController@index');
});
或者,如果我们想指定未命名的中间件,可以直接通过类名使用它:
Route::get('/home', 'HomeController@index')->middleware(App\Http\Middleware\Authenticate::class);
5.1 中间件参数
有时候,中间件需要接收一些额外的参数以启用某些实际情况,例如我们需要确定允许请求的速率和同时请求的次数。Laravel框架提供了很好的支持,从而允许我们传递参数。以下是如何在路由和HTTP内核中传递中间件参数的示例:
// http kernel
class Kernel extends HttpKernel {
protected $middlewareGroups = [ //...
'api' => [
'throttle:api_requests/duration_in_minutes',
],
//...
];
}
// routes
Route::group(['middleware' => 'throttle:api_requests/duration_in_minutes'], function() {
// ...
});
在上面的示例中,Laravel框架的throttle中间件接受两个参数:请求数和持续时间(分钟)。因此,通过在路由中指定中间件参数,可以指定特定路由的限制器规则。
6. 总结
本文主要介绍了Laravel中间件的基础知识,让我们了解了Laravel中间件,如何定义中间件组,如何使用预定义的中间件以及如何编写自己的中间件。在实际应用中,中间件是非常有用的,它可以简化应用程序的开发和管理过程,并且可以帮助我们更好的维护和扩展我们的应用程序。