Tự học Laravel: (30) MIDDLEWARE

Now that I can log in, I would like to limit the creation, editing, and deletion of articles so that I can not execute them without logging in. Laravel performs these filtering in the middleware.

MIDDLEWARE

Middleware that developers should modify is stored in the following directory:

app/Http/Middleware/
├── CheckForMaintenanceMode.php
├── EncryptCookies.php
├── RedirectIfAuthenticated.php
├── TrimStrings.php
├── TrustProxies.php
└── VerifyCsrfToken.php

In addition, there are many middleware provided by the Laravel framework itself under vendor/laravel/framework.

Take a look at RedirectIfAuthenticated.php.

<?php
// app/Http/Middleware/RedirectIfAuthenticated.php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Support\Facades\Auth;
 
class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect('/home');
        }
 
        return $next($request);
    }
}

The point is the handle method. 
The handle method is called before the controller method is called from the root. 
In the handle method, we decide whether to move on to the next step of the application. 
RedirectIfAuthenticated.php redirects to ‘/home’ if you are logged in.
If you are not logged in, call the $next () callback to continue processing.

It seems to be middleware to prevent access when logging in from the file name and the contents of this process.

REGISTRATION OF MIDDLEWARE

Register middleware to the system in app/Html/Kernel.php.

<?php
//app/Html/Kernel.php
 
namespace App\Http;
 
use Illuminate\Foundation\Http\Kernel as HttpKernel;
 
class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];
 
    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
 
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];
 
    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\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,
    ];
}

GLOBAL MIDDLEWARE

Middleware that you want to apply to all HTTP requests is registered in $middleware array.

ROOT MIDDLEWARE

The middleware you want to apply per route is registered with the key in the $routeMiddleware array.
To apply middleware to the root, set as follows.

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

MIDDLEWARE GROUP

If you want to apply multiple middleware with one key, register it in the $ middlewareGroups array.

ROOT MIDDLEWARE APPLICATION STATUS

The application status of the route middleware can be checked with the artisan route: list command.

artisan route:list

+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +
| Domain | Method    | URI                     | Name             | Action                                                                 | Middleware   |
+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +
|        | GET|HEAD  | /                       | home             | App\Http\Controllers\ArticlesController@index                          | web          |
|        | GET|HEAD  | about                   | about            | App\Http\Controllers\PagesController@about                             | web          |
|        | GET|HEAD  | api/user                |                  | Closure                                                                | api,auth:api |
|        | POST      | articles                | articles.store   | App\Http\Controllers\ArticlesController@store                          | web          |
|        | GET|HEAD  | articles                | articles.index   | App\Http\Controllers\ArticlesController@index                          | web          |
|        | GET|HEAD  | articles/create         | articles.create  | App\Http\Controllers\ArticlesController@create                         | web          |
|        | DELETE    | articles/{article}      | articles.destroy | App\Http\Controllers\ArticlesController@destroy                        | web          |
|        | PUT|PATCH | articles/{article}      | articles.update  | App\Http\Controllers\ArticlesController@update                         | web          |
|        | GET|HEAD  | articles/{article}      | articles.show    | App\Http\Controllers\ArticlesController@show                           | web          |
|        | GET|HEAD  | articles/{article}/edit | articles.edit    | App\Http\Controllers\ArticlesController@edit                           | web          |
|        | GET|HEAD  | contact                 | contact          | App\Http\Controllers\PagesController@contact                           | web          |
|        | GET|HEAD  | dashboard               | dashboard        | App\Http\Controllers\DashboardController@index                         | web,auth     |
|        | POST      | login                   |                  | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | GET|HEAD  | login                   | login            | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST      | logout                  | logout           | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | POST      | password/email          | password.email   | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | POST      | password/reset          |                  | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD  | password/reset          | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | GET|HEAD  | password/reset/{token}  | password.reset   | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | POST      | register                |                  | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
|        | GET|HEAD  | register                | register         | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |
+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +

The middleware item on the far right shows the middleware applied to each route. 
Articles related routes are applied to the web. 
Authentication-related routes apply to web and auth or guest.

Actually, web middleware is applied to all routes defined in routes / web.php. So the web is applied to articles related routes that are not supported such as middleware application.

Middleware can be applied not only by setting routes (routes / web.php) but also by the controller. Middleware is applied on the controller for authentication related routes. 
Take a look at LoginController.php.

<?php
// app/Http/Controllers/Auth/LoginController.php
 
...
 
class LoginController extends Controller
{
    ...
 
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

The guest middleware is applied to this controller in the constructor. 
However, there is also support for excluding the logout method.

ACCESS CONTROL BY LOGIN STATUS

The introduction has become long, but I think that middleware has been understood to some extent so far. I will return to the implementation from here.

SCENARIO

What I want to do is …

  • Articles can be registered and edited only when logged in.

That is …

  • Redirect to the login screen when the article registration screen and editing screen are accessed when you are not logged in.
  • When you are not logged in, the article registration button and edit button are not displayed.

Such an implementation is required. 
Among the things I have seen so far, auth middleware seems to be usable.

CONTROLLER

Add middleware settings to the controller.

<?php
// app/Http/Controllers/ArticlesController.php
 
...
 
class ArticlesController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth')
            ->except(['index', 'show']);
    }
 
    ...
}

Check the route with the artisan command.

php artisan route:list

+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +
| Domain | Method    | URI                     | Name             | Action                                                                 | Middleware   |
+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +
|        | POST      | articles                | articles.store   | App\Http\Controllers\ArticlesController@store                          | web,auth     |
|        | GET|HEAD  | articles                | articles.index   | App\Http\Controllers\ArticlesController@index                          | web          |
|        | GET|HEAD  | articles/create         | articles.create  | App\Http\Controllers\ArticlesController@create                         | web,auth     |
|        | DELETE    | articles/{article}      | articles.destroy | App\Http\Controllers\ArticlesController@destroy                        | web,auth     |
|        | PUT|PATCH | articles/{article}      | articles.update  | App\Http\Controllers\ArticlesController@update                         | web,auth     |
|        | GET|HEAD  | articles/{article}      | articles.show    | App\Http\Controllers\ArticlesController@show                           | web          |
|        | GET|HEAD  | articles/{article}/edit | articles.edit    | App\Http\Controllers\ArticlesController@edit                           | web,auth     |
+ -------- + ----------- + ------------------------- + - ---------------- + --------------------------------- --------------------------------------- + ---------- ---- +

※ The above table is narrowed down to articles.

The auth middleware has been applied to routes other than index and show.

Please try to access the following URL while logged out. You should be redirected to the login screen.

※ Please replace the above {id} part with the existing ID.

VIEW

Modify View to control button display according to login status.

{{-- resources/views/articles/index.blade.php --}}
@extends('layout')
 
@section('content')
        <h1>
            Articles
            @auth
                <a href="{{ route('articles.create') }}" class="btn btn-primary float-right">Create New</a>
            @endauth
        </h1>
 
        <hr/>
 
    @foreach($articles as $article)
        ...
    @endforeach
@endsection
{{-- resources/views/articles/show.blade.php --}}
@extends('layout')
 
@section('content')
    <h1>{{ $article->title }}</h1>
 
    <hr/>
 
    <article>
        <div class="body">{{ $article->body }}</div>
    </article>
 
    <br>
 
    <div>
        @auth
            <a href="{{action('ArticlesController@edit',[$article->id])}}" class="btn btn-primary">Edit</a>
 
            {!! delete_form(['articles', $article->id]) !!}
        @endauth
 
        <a href="{{ route('articles.index') }}" class="btn btn-secondary float-right">
            Back
        </a>
    </div>
@endsection

Please try displaying article list screen and article display screen while logged out. You should not see the button.

GUEST MIDDLEWARE DEBUGGING

In the root where guest middleware is applied, I want it to be redirected to the dashboard when accessed while logged in. How is it?

If you access http://localhost:8000/login while logged in …

Sorry, the page you are looking for could not be found.

It was displayed that the page was not found.

It is this that I said that I found a bug while looking at RedirectIfAuthenticated.php above.

Modify RedirectIfAuthenticated.php.

<?php
// app/Http/Middleware/RedirectIfAuthenticated.php
 
...
 
class RedirectIfAuthenticated
{
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            // return redirect('/home');
            return redirect(route('dashboard'));
        }
 
        return $next($request);
    }
}

Once again, accessing http://localhost:8000/login while logged in … 
you should now see the dashboard.

CREATE NEW MIDDLEWARE

Use the artisan command to create new middleware.

php artisan make:middleware MyMiddleware

app/Http/Middleware/MyMiddleware.php is created.

<?php
namespace App\Http\Middleware;
 
use Closure;
 
class MyMiddleware {
 
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
 
}

SUMMARY

You can do the following things.

  • Create new middleware
  • Registration of middleware to the system
  • Access control using middleware

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.