Laravel 路由、中间件及 CSRF

前言

Laravel 路由、中间件及 CSRF。

路由

基本路由

<?php
Route::prefix('v1')->namespace('Api')->group(function () {
    // 系统时间
    Route::get('time', 'IndexController@time')->name('index.time');
    // 需要证验权限的分组
    Route::middleware('check.sign')->group(function () {
        // 图片列表(含搜索)
        Route::get('/photos', 'PhotosController@index')->name('photos.index');
        // 创建表单
        Route::get('/photos/create', 'PhotosController@create')->name('photos.create');
        // 保存图片
        Route::post('/photos', 'PhotosController@store')->name('photos.store');
        // 国片详情
        Route::get('/photos/{id}', 'PhotosController@show')->name('photos.show');
        // 编辑表单
        Route::get('/photos/{id}/edit', 'PhotosController@edit')->name('photos.edit');
        // 更新图片
        Route::put('/photos/{id}', 'PhotosController@update')->name('photos.update');
        // 删除图片
        Route::delete('/photos/{id}', 'PhotosController@destroy')->name('photos.destroy');
    });
});
Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function () {
    // 跳至登录
    Route::redirect('/manage', '/admin/login', 301);
    // 登录页面
    Route::view('/login', 'admin.login')->name('admin.login');
    // 退出登录
    Route::get('/logout/{id?}', 'AdminController@login')->name('admin.logout');
});
// 事件推送
Route::any('wechat/push', 'WechatController@push')->name('wechat.push');
// 视图路由
Route::view('/', 'welcome', ['name' => 'Taylor']);
// 重定向路由
Route::redirect('/here', '/there', 301);
// 限流路由
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
});

资源路由

动词 路径 方法 路由
get /photos index photos.index
get /photos/create create photos.create
post /photos store photos.store
get /photos/{id} show photos.show
get /photos/{id}/edit edit photos.edit
put/patch /photos/{id} update photos.update
delete /photos/{id} destroy photos.destroy

一般资源路由定义:

Route::resource('photos', 'PhotosController');

等于以下路由定义:

Route::get('/photos', 'PhotosController@index')->name('photos.index');
Route::get('/photos/create', 'PhotosController@create')->name('photos.create');
Route::post('/photos', 'PhotosController@store')->name('photos.store');
Route::get('/photos/{id}', 'PhotosController@show')->name('photos.show');
Route::get('/photos/{id}/edit', 'PhotosController@edit')->name('photos.edit');
Route::put('/photos/{id}', 'PhotosController@update')->name('photos.update');
Route::delete('/photos/{id}', 'PhotosController@destroy')->name('photos.destroy');

使用 resource 方法时,如果仅使用到部分路由,必须使用 only 列出所有可用路由:

Route::resource('photos', 'PhotosController', ['only' => ['index', 'show']]);

切记不要使用 except,因为 only 相当于白名单,相对于 except 更加直观,路由使用白名单有利于养成『安全习惯』。

如果你想创建资源控制器,则可以使用如下类似方法:

$ php artisan make:controller PhotosController --resource

生成链接

如果为路由指定了名称后,就可以使用全局辅助函数 route 来生成链接,如果路由有参数,则可以把参数作为 route 函数的第二个参数传入,指定的参数将会自动插入到 URL 中对应的位置,比如:

Route::get('/photos/{id}', 'PhotosController@show')->name('photos.show');
$url = route('photos.show', ['id' => 1]);

中间件

中间件提供了一种方便的机制过滤进入应用程序的 HTTP 请求。这些中间件可以用来执行各种任务,Laravel 自带了一些中间件,包括身份验证、CSRF 保护等。所有的这些中间件都位于 app/Http/Middleware 目录。

创建一个中间件

$ php artisan make:middleware CheckAge

前置中间件

<?php
namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // 执行一些任务
        return $next($request);
    }
}

后置中间件

<?php
namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        // 执行一些任务
        return $response;
    }
}

注册中间件

全局中间件

如果你希望中间件在应用处理每个 HTTP 请求期间运行。只需要在 app/Http/Kernel.php 中的 $middleware 属性中列出这个中间件。

路由中间件

假设你想为指定的路由分配中间件 ,首先应该在 app/Http/Kernel.php 文件内为该中间件分配一个键。默认情况下,该类中的 $routeMiddleware 属性下包含了 Laravel 内置的中间件。若要加入自定义的中间件,只需把它附加到列表后并为其分配一个自定义键。

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,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

一旦在 HTTP 内核中定义好了中间件,就可以通过 middleware 方法将为路由分配中间件:

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

路由中间组

某些时候你可能希望使用一个键把多个中间件打包成一个组,以便更容易地分配给路由。你可以使用 Http 核心的 $middlewareGroups 属性。

中间件组可以使用与单个中间件相同的语法将自身分配给路由和控制器动作。同样,中间件组使得一次将多个中间件分配给一个路由更加方便。

排序中间件

很少情况下,你可能需要中间件以特定的顺序执行,但是当它们被分配到路由时,你无法控制它们的顺序。在这种情况下,可以使用 app/Http/Kernel.php 文件的 $middlewarePriority 属性指定中间件优先级。

Terminable 中间件

有时,在准备好 HTTP 响应之后,中间件可能需要做一些工作。如果你在中间件上定义了一个 terminate 方法,并且你使用的是 FastCGI ,那么它将会在响应准备发送到浏览器之后自动调用。

<?php
namespace Illuminate\Session\Middleware;

use Closure;

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

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

terminate 方法应该同时接收请求和响应。定义了这个中间件之后,别忘了将它添加到路由列表或者 app/Http/Kernel.php 文件的全局中间件中。

CSRF

Laravel 可以轻松使地保护你的应用程序免受 跨站请求伪造 (CSRF) 攻击。 跨站点请求伪造是一种恶意攻击,它凭借已通过身份验证的用户身份来运行未经过授权的命令。

Laravel 会自动为每个活跃的用户的会话生成一个 CSRF「令牌」。该令牌用于验证经过身份验证的用户是否是向应用程序发出请求的用户。

HTML 表单

<form method="POST" action="/profile">
    @csrf
</form>

JavaScript

当构建由 JavaScript 驱动的应用时,可以方便的让 JavaScript HTTP
函数库发起每一个请求时自动附上 CSRF 令牌。默认情况下,resources/js/bootstrap.js 文件中提供的 Axios HTTP 库会使用 cookie 中加密的 XSRF-TOKEN 的值然后在请求时自动发送 X-XSRF-TOKEN 标头。 如果不使用此库,则需要为应用程序手动配置此行为。

<meta name="csrf-token" content="{{ csrf_token() }}">
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

总结

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