laravel8学习1-2

jiang 发表于2021-02-10 14:25:03 最后修改于2025-01-23 00:44:39 3868

中间件

定义中间件

php artisan make:middleware CheckAge

这个命令会在 app/Http/Middleware 目录下创建一个新的中间件类 CheckAge,在这个中间件中,我们只允许提供的 age 大于 200 的请求才能访问应用该中间件的路由,否则,我们会将用户重定向到 / URI:

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->age <= 200) {
            return redirect('/');
        }

        return $next($request);
    }
}

请求之前/之后的中间件

namespace App\Http\Middleware;

use Closure;

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

        return $next($request);
    }
}
namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Perform action 请求之后

        return $response;
    }
}

注册中间件

中间件分三类,分别是全局中间件、中间件组(如web、api)和指定路由中间件(如auth),他们在 app/Http/Kernel.php 文件中被注册

// 在 App\Http\Kernel 类中...   
/**
 * 应用的路由中间件列表
 *
 * 这些中间件可以分配给路由组或者单个路由
 *
 * @var array
 */
protected $routeMiddleware = [
    'age' => \App\Http\Middleware\CheckAge::class,
];

使用中间件

Route::get('/hello', function () {
    //do something
})->middleware('age', 'auth');

下面也可以,但是不推荐。

use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
    //do something
})->middleware(CheckAge::class);

中间件在路由组中排除单个路由

分配中间件到路由群组时,你可能偶尔需要阻止中间件被应用到群组中的单个路由,这可以通过使用 withoutMiddleware 方法来实现

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

    // 该路由不会应用 CheckAge 中间件
    Route::get('admin/profile', function () {
        //
    })->withoutMiddleware('age');
});

中间件参数

额外的中间件参数会在 $next 参数之后传入中间件:


namespace App\Http\Middleware;

use Closure;

class CheckRole
{
    /**
     * 处理输入请求
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @param string $role
     * @return mixed
     * translator http://laravelacademy.org
     */
    public function handle($request, Closure $next, $role, $age)
    {
        if ($request->user()->hasRole($role) && $request->user()->age > $age) {
            // do something
        }

        return $next($request);
    }

}

中间件参数可以在定义路由时通过 : 分隔中间件名和参数名来指定,多个中间件参数可以通过逗号分隔:

Route::get('post/{id}', function ($id) {
    //
})->middleware('role:editor,18');

CSRF防护

添加csrf防护

跨站请求伪造(CSRF)是一种通过伪装授权用户的请求来攻击授信网站的恶意漏洞

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

排除指定URL不做CSRF安全校验

可以在 VerifyCsrfToken 中间件中将要排除的 URL 添加到 $except 属性数组


namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * 从 CSRF 验证中排除的 URL
     *
     * @var array
     */
    protected $except = [
        'alipay/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

除了将 CSRF 令牌作为 POST 参数进行验证外,还可以通过设置 X-CSRF-Token 请求头来实现验证,VerifyCsrfToken 中间件会检查 X-CSRF-TOKEN 请求头。实现方式如下,首先创建一个 meta 标签并将令牌保存到该 meta 标签

<meta name="csrf-token" content="{{ csrf_token() }}">

然后在 js 库(如 jQuery)中添加该令牌到所有请求头,这为基于 AJAX 的请求提供了简单、方便的方式来避免 CSRF 攻击:

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

控制器

定义控制器

所有的 Laravel 控制器应该继承自 Laravel 自带的控制器基类 App\Http\Controllers\Controller(基类控制器提供了很多便捷的方法供子类使用,比如 middleware 等)

php artisan make:controller UserController

单一动作控制器

如果你想要定义一个只处理一个动作的控制器,可以在这个控制器中定义 __invoke 方法:

namespace App\Http\Controllers;

use App\Models\User;
use App\Http\Controllers\Controller;

class ShowProfile extends Controller
{
    /**
     * 展示给定用户的个人主页          
     *
     * @param  int  $id
     * @return Response
     */
    public function __invoke($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

当你为这个单动作控制器注册路由的时候,不需要指定方法:

Route::get('user/{user}',\App\Http\Controllers\ShowProfile::class);

这背后的原理是在 PHP 中当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

你可以通过以下 Artisan 命令快速创建单一动作控制器,只需带上 --invokable 选项即可:

php artisan make:controller ShowProfile --invokable

控制器中间件

在控制器的构造函数中设置中间件更方便,你可以使用基类提供的 middleware 方法轻松分配中间件给该控制器的动作,你甚至可以限制中间件只应用到该控制器类的指定方法,由于闭包函数在真正使用的时候才会执行,所有这个功能可用于在控制器中获取 Session 数据(众所周知,在 Laravel 控制器中不能直接获取 Session 数据)

class UserController extends Controller
{
    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        // auth 中间件会应用到所有方法
        $this->middleware('auth');

        // log 中间件只会应用到 index 方法
        $this->middleware('log')->only('index');

        // subscribed 中间件会应用到 store 之外的所有方法
        $this->middleware('subscribed')->except('store');

        // 使用闭包注册中间件,这为我们定义只在某个控制器使用的中间件提供了方便(无需定义完整的中间件类)
        $this->middleware(function ($request, $next) {
            // do something
            return $next($request);
        });
    }
}

资源控制器

Laravel 的资源控制器可以让我们很便捷地构建基于资源的 RESTful 控制器

php artisan make:controller PostController --resource

指定资源控制器关联的模型类

如果你使用了路由模型绑定,并且想要在资源控制器的方法中对模型实例进行依赖注入,可以在生成控制器的使用使用 --model 选项:

php artisan make:controller PostController --resource --model=Post

这个控制器包含了每一个资源操作对应的方法:


namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

可以通过 Route 的 resource 方法为该控制器注册一个资源路由:


Route::resource('posts', \App\Http\Controllers\PostController::class);

你可以通过传递数组到 resources 方法从而一次注册多个资源控制器:

Route::resources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

部分资源路由


Route::resource('posts', PostController::class, ['only' => 
    ['index', 'show']
]);

Route::resource('posts', PostController::class, ['except' => 
    ['create', 'store', 'update', 'destroy']
]);

资源控制器的处理动作

请求方式 URI路径 控制器方法 路由名称 用途
GET /posts index posts.index 获取所以资源的信息
GET /posts/create create posts.create 获取创建资源的页面
POST /posts store posts.store 提交创建资源的申请
GET /posts/{post} show posts.show 获取某个特定的资源的信息
GET /posts/{post}/edit edit posts.edit 获取编辑某个特定资源的编辑页面
PUT/PATCH /posts/{post} update posts.update 提交某个特定资源的更新申请
DELETE /posts/{post} destroy posts.destroy 提交某个资源的删除申请

API 资源路由

声明被 API 消费的资源路由时,你可能需要排除展示 HTML 模板的路由,如 createedit,为了方便起见,Laravel 提供了 apiResource 方法自动排除这两个路由:

Route::apiResource('posts', PostController::class);

同样,你可以传递数组到 apiResources 方法以便一次注册多个 API 资源控制器:


Route::apiResources([
    'photos' => PhotoController::class,
    'posts' => PostController::class,
]);

要想快速生成不包含 create 或 edit 方法的 API 资源控制器,可以在执行 make:controller 命令时使用 --api 开关:

php artisan make:controller API/PostController --api


小提示 now
头像
这里还没有评论,快评论吧。
头像

jiang

积土而为山,积水而为海。

Copyright © 2017-2020 嘉丽谷 版权所有