laravel 基础教程 —— 中间件

中间件

简介

HTTP 中间件为你的应用提供了一种便利的机制去过滤客户端的请求,比如说laravel中自带的用来验证用户是否已经认证的中间件,如果用户的认证没有通过,那么他将被重定向到登录视图。而如果用户已经通过认证,那么他的请求就会被认证中间件通过,并将请求传递给应用。

中间件可以处理多种任务,不仅仅只是用于验证用户认证。比如你可以创建一个跨同源策略的中间件,用来处理每个请求在被响应前添加正确的响应头,你还可以创造一个日志中间件,在应用被请求时优先记录下请求信息。

Laravel框架本身提供了一些中间件,它们包括维护、认证、csrf保护、session等中间件,这些中间件都被定义在app\Http\Middleware目录中。

定义中间件

为了创建一个新的中间件,你可以直接使用laravel提供的 make:middleware artisan命令:

php artisan make:middleware AgeMiddleware

这条命令会在app\Http\Middleware目录下创建一个AgeMiddleware.php文件。我们创造这么一个中间件,让只有年龄大于200的路由通过:

<?php

namespace App\Http\Middleware;

use Closure;

class AgeMiddleware {
  public function handle ($request, Closure $next) {
    if ($request->get('age') > 200) {
      return $next($request);
    }
    return redirect('home'); 
  }
}

你可以看到,如果请求中所提供的年龄小于等于200,请求将被直接返回一个重定向信息到客户端,而如果年龄大于200,请求将被中间件继续传递给应用。为了在中间件中将请求转交给应用,你可以使用$next回调函数,并将$request传递进去。

你可以建立一系列的中间件来过滤客户端的请求,这样每一层中间件都可以检查请求,如果通过,则将请求转交到下一层,如果不通过则直接被驳回。

前行/后行 中间件

其实,在中间件中不仅仅可以定义前行中间件,即在请求被转交到应用之前进行处理的中间件。

<?php 

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware {
  public function handle ($request, Closure $next) {
    // Perform action

    return $next($request);
  }
}

也可以定义优先转交请求给应用的后执行中间件。

<? php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware {
  public function handle ($request, Closure $next) {
    $response = $next($request);
    // Perform action
    return $response;
  }
}

注册中间件

全局中间件

如果你需要一个可以过滤所有请求的中间件,那么你可以注册一个全局中间件。你需要先定义好中间件,然后在app/Http/kernel.php中的$middleware数组属性中进行追加注册。

分配中间件到路由

如果你想要分配中间件到特定的路由,那么你需要在app/Http/kernel.php文件中$routeMiddleware属性中进行追加注册,在这里你应该定义一个短字符的别名,以便于你在路由分配时快速指定。

// Within App\Http\Kernel Class...

protected $routeMiddleware = [
  'auth' => \App\Http\Middleware\Authenticate::class,
  'auth.basic' => \App\Http\Middleware\AuthenticateBasicAuth::class,
  'gust' => \App\Http\Middleware\RedirectIfAuthenticated::class,
  'throttle' => \App\Http\Middleware\ThrottleRequest::class,
];

一旦你的中间件被注册在了kernel文件中,那么你就可以在定义路由时使用middleware选项进行中间件分配:

Route::get('admin/profile', ['middleware' => 'auth', function () {
  // 
}]);

你可以通过这么做来分配多个中间件:

Route::get('/', ['middleware' => ['first', 'second'], function () {
  // 
}]);

当然laravel也允许你通过链式方法middleware去进行中间件分配:

Route::get('/', function () {
 // 
})->middleware(['first', 'second']);

事实上,你也可以使用完全类名来进行中间件分配:

use App\Http\Middleware\FooMiddleware;

Route::get('admin/profile', ['middleware' => FooMiddleware::class, function () {
  // 
}]);

中间件组

有时候你可能希望在分配路由时,可以通过一个别名来分配一系列的中间件到路由。你可以在kernel文件中使用$middlewareGroups属性来进行注册.

laravel自带了webapi中间件组:

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,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];

一旦注册了中间件组,你可以使用相同语法去分配中间件组到路由:

Route::get('/', ['middleware' => ['web'], function () {
  // 
}]);

事实上,laravel自带的web中间件组已经被默认启用,所有在routes.php中被定义的路由都被分配了此中间件。你可以在RouteServiceProvider.php文件中进行修改.

带参数的中间件

中间件也可以接收额外的自定义参数。比如说你可能需要一个中间件来验证已认证的用户的权限问题。你可能需要传递一个角色名称参数来执行相应的行为.那么你需要创建一个RoleMiddleware来接收一个角色名称作为额外的参数.
额外的参数将会被传递在$next参数之后:

<?php

namesapce App\Http\Middleware;

use Closure;

class RoleMiddleware {
  public function handle ($request, Closure $next, $role) {
    if (!$request->user()->hasRole($role)) {
      // Redirect...
    }

    return $next($request);
  }
}

带参数的中间件在分配给路由时需要在中间件别名之后跟:来分割别名和参数,多个参数需要使用,分隔:

Route::post('post/{id}', ['middleware' => 'role:editor', function ($id) {
  // 
}]);

末端中间件

有时候你可能需要在响应被发送到客户端之后继续处理一些任务,比如说 session中间件在laravel中就是响应被发送出去之后才将session信息进行存储操作。这时候你可以通过在中间件中添加terminate方法来定义一个末端中间件:

<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession {
  public function hanlde ($request, Closure $next) {
    return $next($request);
  }

  public function terminate($request, $response) {
    // Store the sessin data...
  }
}

terminate方法会接收请求和响应,一旦你定义了一个末端中间件,你应该在kernel文件中将其添加到全局中间件中.

每当中间件中的terminate方法被调用,laravel都会从服务容器中返回一个新的中间件实例,如果你想使用同一个实例,你应该将其注册在服务容器中并使用singleton方法注册.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 路由 路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。路由发生在OSI网络参考模型中的...
    Dearmadman阅读 2,854评论 2 9
  • 简介 laravel 使实施认证的变得非常简单,事实上,它提供了非常全面的配置项以适应应用的业务。认证的配置文件存...
    Dearmadman阅读 6,121评论 2 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 0.1配置1.模板继承2.控制器3.git4.支付宝支付的流程5.路由6.中间件7.请求8.laravel 学习笔...
    云龙789阅读 806评论 0 5
  • github地址,欢迎大家提交更新。 express() express()用来创建一个Express的程序。ex...
    Programmer客栈阅读 2,503评论 0 1