Skip to content

미들웨어

소개

미들웨어는 애플리케이션으로 들어오는 HTTP 요청을 검사하고 필터링하는 편리한 메커니즘을 제공합니다. 예를 들어, Laravel은 애플리케이션 사용자가 인증되었는지 확인하는 미들웨어를 포함합니다. 사용자가 인증되지 않은 경우, 미들웨어는 사용자를 애플리케이션의 로그인 화면으로 리디렉션합니다. 그러나 사용자가 인증된 경우, 미들웨어는 요청이 애플리케이션 내부로 더 진행되도록 허용합니다.

인증 외에도 다양한 작업을 수행하기 위해 추가 미들웨어를 작성할 수 있습니다. 예를 들어, 로깅 미들웨어는 애플리케이션으로 들어오는 모든 요청을 기록할 수 있습니다. Laravel에는 인증 및 CSRF 보호를 위한 미들웨어를 포함하여 다양한 미들웨어가 포함되어 있지만, 사용자 정의 미들웨어는 일반적으로 애플리케이션의 app/Http/Middleware 디렉토리에 있습니다.

미들웨어 정의

새로운 미들웨어를 생성하려면 make:middleware Artisan 명령어를 사용하세요.

php artisan make:middleware EnsureTokenIsValid

이 명령어는 app/Http/Middleware 디렉토리 내에 새로운 EnsureTokenIsValid 클래스를 생성합니다. 이 미들웨어에서 제공된 token 입력값이 지정된 값과 일치하는 경우에만 경로에 대한 액세스를 허용합니다. 그렇지 않으면 사용자를 /home URI로 리디렉션합니다.

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureTokenIsValid
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->input('token') !== 'my-secret-token') {
return redirect('/home');
}
 
return $next($request);
}
}

보시다시피, 주어진 token이 비밀 토큰과 일치하지 않으면 미들웨어는 클라이언트에 HTTP 리디렉션을 반환합니다. 그렇지 않으면 요청이 애플리케이션으로 더 전달됩니다. 요청을 애플리케이션 깊숙이 전달하려면(미들웨어가 "통과"하도록 허용하려면) $next 콜백을 $request와 함께 호출해야 합니다.

미들웨어는 HTTP 요청이 애플리케이션에 도달하기 전에 통과해야 하는 일련의 "레이어"로 생각하는 것이 가장 좋습니다. 각 레이어는 요청을 검사하고 완전히 거부할 수도 있습니다.

lightbulb

모든 미들웨어는 서비스 컨테이너를 통해 확인되므로 미들웨어의 생성자 내에서 필요한 모든 종속성을 타입 힌트할 수 있습니다.

미들웨어 및 응답

물론, 미들웨어는 요청을 애플리케이션 깊숙이 전달하기 전이나 후에 작업을 수행할 수 있습니다. 예를 들어, 다음 미들웨어는 요청이 애플리케이션에서 처리되기 에 일부 작업을 수행합니다.

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class BeforeMiddleware
{
public function handle(Request $request, Closure $next): Response
{
// 액션 수행
 
return $next($request);
}
}

그러나 이 미들웨어는 요청이 애플리케이션에서 처리된 에 작업을 수행합니다.

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class AfterMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
 
// 액션 수행
 
return $response;
}
}

미들웨어 등록하기

글로벌 미들웨어

애플리케이션에 대한 모든 HTTP 요청 중에 미들웨어를 실행하려면 애플리케이션의 bootstrap/app.php 파일의 글로벌 미들웨어 스택에 추가할 수 있습니다.

use App\Http\Middleware\EnsureTokenIsValid;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->append(EnsureTokenIsValid::class);
})

withMiddleware 클로저에 제공된 $middleware 객체는 Illuminate\Foundation\Configuration\Middleware의 인스턴스이며 애플리케이션의 경로에 할당된 미들웨어를 관리하는 역할을 합니다. append 메서드는 미들웨어를 글로벌 미들웨어 목록의 끝에 추가합니다. 목록의 시작 부분에 미들웨어를 추가하려면 prepend 메서드를 사용해야 합니다.

Laravel의 기본 글로벌 미들웨어 수동 관리

Laravel의 글로벌 미들웨어 스택을 수동으로 관리하려면 use 메서드에 Laravel의 기본 글로벌 미들웨어 스택을 제공할 수 있습니다. 그런 다음 필요에 따라 기본 미들웨어 스택을 조정할 수 있습니다.

->withMiddleware(function (Middleware $middleware) {
$middleware->use([
\Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class,
// \Illuminate\Http\Middleware\TrustHosts::class,
\Illuminate\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Http\Middleware\ValidatePostSize::class,
\Illuminate\Foundation\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]);
})

경로에 미들웨어 할당하기

특정 경로에 미들웨어를 할당하려면 경로를 정의할 때 middleware 메서드를 호출하면 됩니다.

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::get('/profile', function () {
// ...
})->middleware(EnsureTokenIsValid::class);

middleware 메서드에 미들웨어 이름의 배열을 전달하여 경로에 여러 미들웨어를 할당할 수 있습니다.

Route::get('/', function () {
// ...
})->middleware([First::class, Second::class]);

미들웨어 제외하기

경로 그룹에 미들웨어를 할당할 때 그룹 내의 개별 경로에 미들웨어가 적용되지 않도록 해야 할 수 있습니다. withoutMiddleware 메서드를 사용하여 이를 수행할 수 있습니다.

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::middleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/', function () {
// ...
});
 
Route::get('/profile', function () {
// ...
})->withoutMiddleware([EnsureTokenIsValid::class]);
});

전체 그룹의 경로 정의에서 주어진 미들웨어 집합을 제외할 수도 있습니다.

use App\Http\Middleware\EnsureTokenIsValid;
 
Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
Route::get('/profile', function () {
// ...
});
});

withoutMiddleware 메서드는 경로 미들웨어만 제거할 수 있으며 글로벌 미들웨어에는 적용되지 않습니다.

미들웨어 그룹

경로에 더 쉽게 할당할 수 있도록 여러 미들웨어를 단일 키로 그룹화하고 싶을 수 있습니다. 애플리케이션의 bootstrap/app.php 파일 내에서 appendToGroup 메서드를 사용하여 이를 수행할 수 있습니다.

use App\Http\Middleware\First;
use App\Http\Middleware\Second;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->appendToGroup('group-name', [
First::class,
Second::class,
]);
 
$middleware->prependToGroup('group-name', [
First::class,
Second::class,
]);
})

미들웨어 그룹은 개별 미들웨어와 동일한 구문을 사용하여 경로 및 컨트롤러 액션에 할당할 수 있습니다.

Route::get('/', function () {
// ...
})->middleware('group-name');
 
Route::middleware(['group-name'])->group(function () {
// ...
});

Laravel의 기본 미들웨어 그룹

Laravel에는 웹 및 API 경로에 적용하고 싶을 수 있는 일반적인 미들웨어를 포함하는 미리 정의된 webapi 미들웨어 그룹이 포함되어 있습니다. Laravel은 이러한 미들웨어 그룹을 해당 routes/web.phproutes/api.php 파일에 자동으로 적용합니다.

web 미들웨어 그룹
Illuminate\Cookie\Middleware\EncryptCookies
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
Illuminate\Session\Middleware\StartSession
Illuminate\View\Middleware\ShareErrorsFromSession
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
Illuminate\Routing\Middleware\SubstituteBindings
api 미들웨어 그룹
Illuminate\Routing\Middleware\SubstituteBindings

이러한 그룹에 미들웨어를 추가하거나 앞에 추가하려면 애플리케이션의 bootstrap/app.php 파일 내에서 webapi 메서드를 사용할 수 있습니다. webapi 메서드는 appendToGroup 메서드의 편리한 대안입니다.

use App\Http\Middleware\EnsureTokenIsValid;
use App\Http\Middleware\EnsureUserIsSubscribed;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
EnsureUserIsSubscribed::class,
]);
 
$middleware->api(prepend: [
EnsureTokenIsValid::class,
]);
})

Laravel의 기본 미들웨어 그룹 항목 중 하나를 사용자 정의 미들웨어로 대체할 수도 있습니다.

use App\Http\Middleware\StartCustomSession;
use Illuminate\Session\Middleware\StartSession;
 
$middleware->web(replace: [
StartSession::class => StartCustomSession::class,
]);

또는 미들웨어를 완전히 제거할 수도 있습니다.

$middleware->web(remove: [
StartSession::class,
]);

Laravel의 기본 미들웨어 그룹 수동 관리

Laravel의 기본 webapi 미들웨어 그룹 내의 모든 미들웨어를 수동으로 관리하려면 그룹을 완전히 재정의할 수 있습니다. 아래 예제에서는 필요에 따라 사용자 정의할 수 있도록 기본 미들웨어를 사용하여 webapi 미들웨어 그룹을 정의합니다.

->withMiddleware(function (Middleware $middleware) {
$middleware->group('web', [
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
]);
 
$middleware->group('api', [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
// 'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
]);
})
lightbulb

기본적으로 webapi 미들웨어 그룹은 bootstrap/app.php 파일에 의해 애플리케이션의 해당 routes/web.phproutes/api.php 파일에 자동으로 적용됩니다.

미들웨어 별칭

애플리케이션의 bootstrap/app.php 파일에서 미들웨어에 별칭을 할당할 수 있습니다. 미들웨어 별칭을 사용하면 지정된 미들웨어 클래스에 대한 짧은 별칭을 정의할 수 있으며, 이는 긴 클래스 이름을 가진 미들웨어에 특히 유용할 수 있습니다.

use App\Http\Middleware\EnsureUserIsSubscribed;
 
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class
]);
})

애플리케이션의 bootstrap/app.php 파일에 미들웨어 별칭이 정의되면 경로에 미들웨어를 할당할 때 별칭을 사용할 수 있습니다.

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

편의를 위해 Laravel의 일부 기본 제공 미들웨어는 기본적으로 별칭이 지정됩니다. 예를 들어, auth 미들웨어는 Illuminate\Auth\Middleware\Authenticate 미들웨어의 별칭입니다. 다음은 기본 미들웨어 별칭 목록입니다.

별칭 미들웨어
auth Illuminate\Auth\Middleware\Authenticate
auth.basic Illuminate\Auth\Middleware\AuthenticateWithBasicAuth
auth.session Illuminate\Session\Middleware\AuthenticateSession
cache.headers Illuminate\Http\Middleware\SetCacheHeaders
can Illuminate\Auth\Middleware\Authorize
guest Illuminate\Auth\Middleware\RedirectIfAuthenticated
password.confirm Illuminate\Auth\Middleware\RequirePassword
precognitive Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests
signed Illuminate\Routing\Middleware\ValidateSignature
subscribed \Spark\Http\Middleware\VerifyBillableIsSubscribed
throttle Illuminate\Routing\Middleware\ThrottleRequests 또는 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis
verified Illuminate\Auth\Middleware\EnsureEmailIsVerified

미들웨어 정렬

드물게 미들웨어가 특정 순서로 실행되어야 하지만 경로에 할당될 때 해당 순서를 제어할 수 없는 경우가 있을 수 있습니다. 이러한 상황에서 애플리케이션의 bootstrap/app.php 파일에서 priority 메서드를 사용하여 미들웨어 우선순위를 지정할 수 있습니다.

->withMiddleware(function (Middleware $middleware) {
$middleware->priority([
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Auth\Middleware\Authorize::class,
]);
})

미들웨어 매개변수

미들웨어는 추가 매개변수를 받을 수도 있습니다. 예를 들어, 애플리케이션이 주어진 작업을 수행하기 전에 인증된 사용자가 지정된 "역할"을 가지고 있는지 확인해야 하는 경우 역할 이름을 추가 인수로 받는 EnsureUserHasRole 미들웨어를 만들 수 있습니다.

추가 미들웨어 매개변수는 $next 인수 뒤에 미들웨어에 전달됩니다.

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class EnsureUserHasRole
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user()->hasRole($role)) {
// 리디렉션...
}
 
return $next($request);
}
 
}

미들웨어 이름과 매개변수를 :로 구분하여 경로를 정의할 때 미들웨어 매개변수를 지정할 수 있습니다.

use App\Http\Middleware\EnsureUserHasRole;
 
Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor');

여러 매개변수는 쉼표로 구분할 수 있습니다.

Route::put('/post/{id}', function (string $id) {
// ...
})->middleware(EnsureUserHasRole::class.':editor,publisher');

종료 가능한 미들웨어

때로는 미들웨어가 HTTP 응답이 브라우저로 전송된 후에 일부 작업을 수행해야 할 수 있습니다. 미들웨어에서 terminate 메서드를 정의하고 웹 서버가 FastCGI를 사용하는 경우 응답이 브라우저로 전송된 후 terminate 메서드가 자동으로 호출됩니다.

<?php
 
namespace Illuminate\Session\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
 
class TerminatingMiddleware
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
 
/**
* 응답이 브라우저로 전송된 후 작업을 처리합니다.
*/
public function terminate(Request $request, Response $response): void
{
// ...
}
}

terminate 메서드는 요청과 응답을 모두 받아야 합니다. 종료 가능한 미들웨어를 정의한 후 애플리케이션의 bootstrap/app.php 파일에서 경로 또는 글로벌 미들웨어 목록에 추가해야 합니다.

미들웨어에서 terminate 메서드를 호출할 때 Laravel은 서비스 컨테이너에서 미들웨어의 새 인스턴스를 확인합니다. handleterminate 메서드가 호출될 때 동일한 미들웨어 인스턴스를 사용하려면 컨테이너의 singleton 메서드를 사용하여 미들웨어를 컨테이너에 등록합니다. 일반적으로 이 작업은 AppServiceProviderregister 메서드에서 수행해야 합니다.

use App\Http\Middleware\TerminatingMiddleware;
 
/**
* 모든 애플리케이션 서비스를 등록합니다.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}