Laravel에서 세션 ID로 인증 상태를 확인하는 상태 저장 API 사용

Laravel은 표준으로 API를 위한 라우팅 및 설정을 제공합니다.
그러나 이러한 설정은 토큰을 이용해 인증 상태를 체크하는 것으로 스테이트리스인 것이 전제가 되고 있습니다.
서버 측에서 렌더링하고, 일부분만 조금 API 경유로 데이터를 취득하고 싶지만, 로그인 세션을 사용해 인증이 끝나면 데이터를 취득하는 API를 만들려고 했을 때에 빠졌기 때문에 메모.

말하기



Laravel에서 세션 ID를 이용하여 바삭바삭하게 API 만드는 방법.

말하지 않는 것



Stateless API가 가장 좋은지 Stateful API라도 좋은지에 대해.
또한 API 디자인 모범 사례에 관하여.

TL;DR



상태 저장 API에서도 요구 사항이 허용되는 경우 상태 저장 API에 대한 설정을 추가하면 즉시 구현할 수 있습니다.
Stateful 용 API 라우팅 파일 routes/statefulApi.php 추가,Providers/RouteServiceProvider.php에서 추가한 라우팅 파일을 로드하고 Http/Kernel.php 전용 미들웨어 그룹을 정의합니다.

환경




이름
버전


PHP
7.1.6

라라벨
5.5.14


수정 전



다음과 같은 API의 라우팅 설정이 있습니다.

routes/api.php
<?php

use Illuminate\Http\Request;

Route::get('/post/index', 'Api\PostController@index');

컨트롤러는 다음과 같습니다.
토큰으로 인증하는 것과 같은 어려운 일은 번거롭고 갑자기 API를 구현하고 싶기 때문에 쿠키에 저장된 세션 ID로 인증되었는지 확인하고 싶기 때문에 middleware는 auth를 지정하고 있습니다.

Http/Controllers/Api/PostController.php
<?php

namespace App\Http\Controllers\Api;

use Illuminate\Http\Request;
use App\Post;
use App\Http\Controllers\Controller;

class PostController extends Controller
{
    /**
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function index(Request $request)
    {
        return Post::all();
    }
}

Kernel.php는 다음과 같습니다. 기본값은 그대로입니다.

Http/Kernel.php
<?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 = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::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,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}

쿠키에 인증된 세션 ID가 저장된 상태에서 위의 API를 실행하면 401 오류가 발생합니다.
그 이유는 web 미들웨어에 \App\Http\Middleware\EncryptCookies::class가 있지만 쿠키 암호화 및 해독을 담당하며 브라우저 쿠키에 저장된 세션 ID는 암호화된 세션 ID가 브라우저에서 API를 실행할 때 암호화된 값이 요청에 부여되지만 web 미들웨어 그룹에 api가 없기 때문에 세션 ID를 해독할 수 없습니다. 에 인증을 확인하면 401 오류가 발생합니다.
또한 해독뿐만 아니라 \App\Http\Middleware\EncryptCookies::class도 필요합니다.

그렇다면 \Illuminate\Session\Middleware\StartSession::class 미들웨어 그룹에 쿠키와 세션 미들웨어를 추가하면 토큰을 전제로 한 상태 비 저장 API에 추가 사항이 있습니다.
따라서 기존 api을 더럽히지 않도록 새 상태 저장 API에 대한 설정을 추가합니다.

상태 저장 API에 대한 설정 추가



전용 라우팅 구성 파일을 추가합니다.

routes/statefulApi.php
<?php

use Illuminate\Http\Request;

Route::get('/post/index', 'Api\PostController@index');

위의 라우팅 구성 파일을 로드하도록 합니다.

Providers/RouteServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * 省略
     */

    /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map()
    {
        $this->mapApiRoutes();

        $this->mapWebRoutes();

        $this->mapStatefulApiRoutes();    // ★追加
    }

    /**
     * 省略
     */

// ★↓↓↓↓↓追加
    /**
     * Define the "statefulApi" routes for the application.
     *
     * These routes are typically stateless.
     *
     * @return void
     */
    protected function mapStatefulApiRoutes()
    {
        Route::prefix('api')
             ->middleware('stateful_api')
             ->namespace($this->namespace)
             ->group(base_path('routes/statefulApi.php'));
    }
// ★↑↑↑↑↑追加
}

Kernel.php에 Stateful API에 대한 설정을 추가합니다.api 미들웨어를 기반으로 세션 ID로 인증하기
쿠키 관련 미들웨어와 StartSession 미들웨어를 추가합니다.

Http/Kernel.php
    /**
     * 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',
        ],

// ★↓↓↓↓↓追加
        'stateful_api' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            'throttle:60,1',
            'bindings',
        ],
// ★↑↑↑↑↑追加
    ];

이렇게 하면 세션 ID로 인증되었는지 확인할 수 있습니다.
액세스 토큰을 발행·관리하는 것은 번거롭고 거기까지 필요하지 않은 경우, 스테이트풀한 API를 사용해 보는 것도 좋을까 생각합니다.

좋은 웹페이지 즐겨찾기