システム開発

CookieによるAPI経由のユーザー認証機能を作る【Laravel6とNuxt.jsで作る管理画面】

PHPの人気のフレームワークLaravelを利用してWebサイトの管理画面を開発することができます。

このシリーズではそんな管理画面の構築に関して、技術者向けにその手順を紹介しています。
この記事ではCookieでAPI経由のユーザー認証機能を作る方法をご紹介!

Nuxt.jsからLaravelのAPIをAjaxで通信できるようにする手順はこちらの記事で解説中。

・Laravelを使って構築をしたい方
・Webサイト構築の具体的な手法が知りたい方

これらに当てはまる方におすすめの記事となっています。このシリーズを読めばLaravel6とNuxt.jsで管理画面を作成することができますよ

最低限やりたいことを決める

まず実装の前に、最低限やりたいことを決めておきます。あれもこれもと機能を詰め込みすぎてしまっても実装に時間がかかってしまい大変です。今回は管理画面を作りたいので、以下の要件にしました。

● ユーザー登録機能は実装せず、事前に用意した管理者ユーザーでログインできる
● /adminにアクセスした際にログインしていない場合は、ログイン画面に遷移する

セッションをDB管理するか決める

ユーザー認証を実装する前にまずセッションの管理方法を決めます。

認証完了後にセッションはスタートし、セッションが有効な間は認証済と扱われてしまうなど、これらは関係が深いのです。

セッション情報には、大きく分けて以下の2つの管理方法があります。

● MySQLやRedis等のDBに保存しておく方法
● Cookieやトークンでデータを都度送る方法

DB管理する方法は外部へのデータ取得が必要になり処理時間がかかってしまいます。また実装が必要になり手間も。

メリットはDBにセッション情報を持っていて、即時セッションを無効にすることが出来るため、
金融系など厳しいセキュリティが求められるサービスには有効です。

一方、Cookieやトークンで都度送る方法は有効期限が切れるまでセッションを無効には出来ませんが、標準サポートされていることも多く、動作も実装のスピードも早いです。

今回は即時セッションを無効にしたい要件でも無いため、データを都度送る方法でセッション管理を行うことにします。

Cookieとトークンどちらを使うか決める

先ほど決めたCookieやトークンでデータを都度送る方法のうち、どちらを選択するかを決めていきます。

トークンを利用する場合は、標準仕様であるJWT(JSON Web Token)に沿った方法を取るのが一般的です。

今回の記事ではトークン(JWT)は使わず、Cookieによる認証機能を採用しています。

本記事では詳述はしませんが、トークン(JWT)を利用する場合は、セキュアなトークンの保存方法や署名のアルゴリズムなど、考えるべき要素が増えるためです。

LaravelのAuthミドルウェアはデフォルトで暗号化されたCookieをサポートしていますし、今回はネイティブアプリでもないため、Cookieを使うことに決めました。

管理者ユーザー用のモデルとテーブルを作成する

まず下記コマンドで管理者ユーザー用のモデルとマイグレーションファイルを作成します。

php artisan make:model AdminUser --migration

Laravel6ではデフォルトで一般ユーザー用のモデルが、app/User.phpに用意されているため、
内容をコピーして以下のようにapp/AdminUser.phpを書き換えます。

<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class AdminUser extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

同様に新しく追加したマイグレーションファイルも下記のように書き換えます。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateAdminUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */    public function up()
    {
        Schema::create('admin_users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */    public function down()
    {
        Schema::dropIfExists('admin_users');
    }
}

次に以下コマンドを実行してDBに反映します。

php artisan migrate

これでadmin_usersテーブルが作成されました。

ログイン用の管理者ユーザーのデータを用意する

次にtinkerでログイン用の管理者ユーザーのデータを用意します。

下記コマンドを実行してtinkerを起動します。

php artisan tinker

次に以下のコマンドでログイン用のデータを作成します。
パスワードはtinker経由だと平文で保存されてしまうため、ハッシュ化を行っています。

AdminUser::create(['name' => 'hoge', 'email' => 'hoge@example.com', 'password' => Hash::make('hogehoge')])

Laravel(API)でCookieを使ったセッション管理を有効にする

LaravelはAPIとして利用する場合、デフォルトの認証方法はトークンを想定しており、
Cookieをレスポンスとして返してはくれません。

そのためapp/Http/Kernel.phpを以下のように編集することで、
フォーム認証(Web)と同様にAPIでもログイン後にセッション情報を暗号化されたCookieで返せるようになります。

/**
* 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' => [
      //ここから
      \App\Http\Middleware\EncryptCookies::class,
      \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
      \Illuminate\Session\Middleware\StartSession::class,
      \Illuminate\View\Middleware\ShareErrorsFromSession::class,
      //ここまで追加
      'throttle:60,1',
      \Illuminate\Routing\Middleware\SubstituteBindings::class,
  ],
];

Authミドルウェアの設定を変更する

次にconfig/auth.phpを下記のように編集して、APIの認証方法をCookieを使ったセッションに変更します。

またパスワード情報はadmin_usersテーブルを参照するようにしています。

本来は一般ユーザーと管理者ユーザーは設定を分けるべきですが、時間がかかってしまうので、一旦全てのAPI認証をadmin_usersテーブルに向けています。

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */
    'defaults' => [
        'guard' => 'api',
        'passwords' => 'admin_users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session", "token"
    |
    */
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'session',
            'provider' => 'admin_users',
        ],

        // 'api' => [
        //     'driver' => 'token',
        //     'provider' => 'users',
        //     'hash' => false,
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        'admin_users' => [
            'driver' => 'eloquent',
            'model' => App\AdminUser::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'admin_users' => [
            'provider' => 'admin_users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */
    'password_timeout' => 10800,

];

ログイン用のルーティングを用意する

routes/api.php を以下のように編集して、ログイン処理と現在ログイン中のユーザーの取得が出来るようにします。

先程の設定でAPIミドルウェアの場合はadmin_usersテーブルを参照するようになったので、
Auth::user()の返り値はログイン中のAdminUserのレコードになります。

Route::group(["middleware" => "api"], function () {
    Route::post('/login', 'Auth\LoginController@login');
    Route::get('/current_admin_user', function () {
        return Auth::user();
    });
});

下記コマンドを実行してルーティングが作成されているか確認します。

php artisan route:list

以下のように表示されていればOKです。

ログイン成功時のレスポンスを変更する

AuthミドルウェアはデフォルトではWebを想定しているため、ログイン後にリダイレクトするようになっています。(参考はこちら

そのため、app/Http/Controllers/Auth/LoginController.phpを以下のように編集することで、
ログイン成功時にリダイレクトではなく、ログインしたユーザー情報を返すように変更しています。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
//追加
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */
    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */    //追加
    protected function authenticated(Request $request, $user)
    {
        return $user;
    }
}

curlコマンドでログインの動作を確認する

以上でAPIのログイン機能は実装が完了しているので、curlコマンドで動作の確認をしてみます。

下記コマンドを実行します。

curl -c cookie.txt -X POST localhost:8000/api/login -d email=hoge@example.com -d password=hogehoge

以下のようなユーザー情報が返ってくればOKです。

Cookieがcookie.txtに出力されるので、次は下記コマンドを実行してログイン中の管理者ユーザーの取得を試します。

curl -b cookie.txt http://localhost:8000/api/current_admin_user

同様に以下のようなユーザー情報が返ってくればOKです。

上記の通り、curl-bオプションをつけると、
出力されたCookie情報を使ってリクエストを投げることが出来ます。

cookie.txtは確認が終わったら削除しておきましょう。

Laravel(API)でCORSの設定を行う

Cookieはデフォルトでは異なるドメインで送受信を行うことは出来ません。

NuxtとLaravelは別ドメインで動かすので、指定したドメイン間の通信を許可するCORS(Cross-Origin Resource Sharing )の設定を行う必要があります。

LaravelのCORS設定にはfruitcake/laravel-corsというライブラリが有名です。

まず下記コマンドでインストールします。

composer require fruitcake/laravel-cors

インストールが完了したらapp/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 = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        //追加
        \Fruitcake\Cors\HandleCors::class,
    ];

次に.envファイルに許可したいクライアント側のドメインを記入しておきます。

CORS_ALLOWED_ORIGIN=http://localhost:3000

記入が完了したら以下のコマンドでCORSの設定ファイルを作成します。

php artisan vendor:publish --tag="cors"

config/cors.phpが作成されるので、下記の内容で編集します。

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Laravel CORS Options
    |--------------------------------------------------------------------------
    |
    | The allowed_methods and allowed_headers options are case-insensitive.
    |
    | You don't need to provide both allowed_origins and allowed_origins_patterns.
    | If one of the strings passed matches, it is considered a valid origin.
    |
    | If array('*') is provided to allowed_methods, allowed_origins or allowed_headers
    | all methods / origins / headers are allowed.
    |
    */
    /*
     * You can enable CORS for 1 or multiple paths.
     * Example: ['api/*']
     */    'paths' => ['api/*'],

    /*
    * Matches the request method. `[*]` allows all methods.
    */    'allowed_methods' => ['*'],

    /*
     * Matches the request origin. `[*]` allows all origins.
     */    'allowed_origins' => [env('CORS_ALLOWED_ORIGIN')],

    /*
     * Matches the request origin with, similar to `Request::is()`
     */    'allowed_origins_patterns' => [],

    /*
     * Sets the Access-Control-Allow-Headers response header. `[*]` allows all headers.
     */    'allowed_headers' => ['*'],

    /*
     * Sets the Access-Control-Expose-Headers response header with these headers.
     */    'exposed_headers' => [],

    /*
     * Sets the Access-Control-Max-Age response header when > 0.
     */    'max_age' => 0,

    /*
     * Sets the Access-Control-Allow-Credentials header.
     */    'supports_credentials' => true,
];

変更している箇所は以下の3点です。

● paths:  指定したパスにのみクロスドメインのリクエストを許可する設定
● allowed_origins: クロスドメインのリクエストを許可するドメインを指定
● supports_credentials: クロスドメインでCookieの送受信を許可する設定

特にpathsはデフォルトで空なのですが、この項目は必ず設定しないとクロスドメインが許可されませんので注意してください。

これで/api以下のレスポンスヘッダに以下の内容が返されるようになり、クロスドメインでのリクエストとCookieの送受信が可能になります。

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: 今回許可したドメイン

Ajax以外のリクエストを制限するミドルウェアを作成する

今のままだと、URLやcurlから直接APIを実行できてしまいます。

NuxtからのAjax通信のみ受け付けるようにしたいので、Ajax以外のリクエストを制限するミドルウェアを作成します。

app/Http/Middlewareに以下の内容のAjaxOnly.phpを追加します。
Ajax通信以外の場合は403エラーを返すという処理です。

<?php

namespace App\Http\Middleware;

use Closure;

class AjaxOnly
{
    public function handle($request, Closure $next)
    {
        if ($request->ajax()) {
            return $next($request);
        }
        abort(403);
    }
}

またapp/Http/Kernel.phpのAPIミドルウェアに追記します。

    /**
     * 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' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            //追加
            \App\Http\Middleware\AjaxOnly::class,
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

これで「許可したドメインからのAjax通信」のみAPIを実行できるようになるため、
curlコマンドはもちろん、許可していない他サイトからのAjax通信も防ぐことが出来ます。

axiosでAjax通信の設定を行う

APIの実装は完了したので、ここからはNuxt側の作業を進めていきます。

クロスドメインの場合、X-Requested-WithヘッダにXMLHttpRequestをつけないと、
API側でリクエストがAjaxであることを判定できません。

そのためaxiosの全部のリクエストにX-Requested-Withヘッダを追加する必要がありますが、
Nuxtではこのような共通設定を行うためにプラグインという仕組みがあります。

まず以下の内容でplugins/axios.jsを作成します。

export default function ({ $axios }) {
  $axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
}

そして次の内容でnuxt.config.jsに設定を追加します。

/*
** Plugins to load before mounting the App
*/plugins: [
  //追加
  '~/plugins/axios'
],

これで全てのaxiosのリクエストにX-Requested-Withヘッダが追加され、
APIを実行しても403エラーにならないようになります。

axiosでCORSの設定を行う

次にNuxt側でもCORSを許可する設定を行っていきます。

まず以下コマンドでdotenvをインストールします。

yarn add @nuxtjs/dotenv

次に以下の内容の.envファイルを作成します。

API_URL=http://localhost:8000/api

作成が完了したら、次はnuxt.config.jsを以下の内容に修正します。

//追加
require('dotenv').config()

export default {
  mode: 'universal',
  /*
  ** Headers of the page
  */  head: {
    title: process.env.npm_package_name || '',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },
  /*
  ** Customize the progress-bar color
  */  loading: { color: '#fff' },
  /*
  ** Global CSS
  */  css: [
  ],
  /*
  ** Plugins to load before mounting the App
  */  plugins: [
    '~/plugins/axios'
  ],
  /*
  ** Nuxt.js dev-modules
  */  buildModules: [
  ],
  /*
  ** Nuxt.js modules
  */  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    //追加
    '@nuxtjs/dotenv',
  ],
  /*
  ** Axios module configuration
  ** See https://axios.nuxtjs.org/options
  */  axios: {
   //追加
    baseURL: process.env.API_URL,
    //追加
    credentials: true
  },
  /*
  ** Build configuration
  */  build: {
    /*
    ** You can extend webpack config here
    */    extend (config, ctx) {
    }
  }
}

特に重要な変更箇所は以下の2点です。

● baseURL: credentialsで許可するドメインのベースURLを指定
● credentials: クロスドメインのCookie送受信を許可する設定

これでクロスドメインでのCookie送受信がクライアント側でも出来るようになります。

ログインした管理ユーザーを保存するStoreを作成する

Nuxtではページを横断してデータを保存するために、Storeというデータを全体で共有する仕組みがあります。

store以下に扱いたいデータの内容と、操作用のメソッドを書いたファイルを記述することで設定が可能です。

今回はログインユーザーを管理したいので、以下の内容のstore/auth.jsを作成します。

これでログイン後にAPIから返ってくる管理者ユーザーのデータを全体で共有できるようになります。

export const state = () => ({
  admin_user: null
})

export const mutations = {
  setAdminUser (state, admin_user) {
    state.admin_user = admin_user
  }
}

export const actions = {
  async login ({ commit }, { email, password }) {
    const response = await this.$axios.$post('/login', { email, password })
      .catch(err => {
        console.log(err)
      })
    commit('setAdminUser', response)
  }
}

APIからログイン中の管理者ユーザーを取得するようにする

Storeのデータはリロードすると消えてしまうため、
画面表示前にAPIからログイン中のユーザー情報を取得して毎回Storeにセットする処理が必要になります。

以下の内容でstore/index.jsを追加します。

export const actions = {
  async nuxtServerInit ({ commit }, { app }) {
    await app.$axios.$get('/current_admin_user')
      .then(admin_user => commit('auth/setAdminUser', admin_user))
      .catch(() => commit('auth/setAdminUser', null))
  }
}

nuxtServerInitはSSR時に実行される処理で、
これでCookieが有効な間はログイン中の管理者ユーザーの情報が毎回セットされるようになります。

ログイン中かをチェックして画面遷移させるミドルウェアを作る

Nuxtには画面の表示前に、何か処理を実行したい時にミドルウェアという仕組みがあります。

今回はログイン中かどうかをチェックして、表示する画面を変更するミドルウェアを作ってみたいと思います。

middlewareに以下の内容のnot_logined_admin_user.jsというファイルを作成します。

export default function ({ store, redirect }) {
  if (!store.state.auth.admin_user) {
    redirect('/admin/login')
  }
}

先ほど作成したStorestate.auth.admin_userがセットされていなければ、ログイン画面に遷移させるという処理になります。

次に同様にmiddleware以下の内容のlogined_admin_user.jsというファイルを作成します。

export default function ({ store, redirect }) {
  if (store.state.auth.admin_user) {
    redirect('/admin')
  }
}

ログイン中の場合は/admin/loginにアクセスしても、ログイン後の画面を表示するために利用します。

ログイン後の画面を作成する

元々の要件が/adminにアクセスした際にログインしていない場合は、ログイン画面に遷移するので、以下の内容のpages/admin/index.vueというファイルを作成します。

<template>
  <section>
    <h1>管理画面へようこそ</h1>
  </section>
</template>

<script>
export default {
  middleware: 'not_logined_admin_user',
}
</script>

先ほど作成したnot_logined_admin_user.jsをミドルウェアとして指定しているため、/adminにアクセスした際にログインしていない場合はログイン画面に遷移されるようになります。

ログイン画面を作成する

次に以下の内容のpages/admin/login.vueというファイルを作成します。

<template>
  <section>
    <h1>Login</h1>
    <form @submit.prevent="submit">
      <div>
        <label for="email">email</label>
        <input type="text" id="email" v-model="email" />
      </div>
      <div>
        <label for="password">password</label>
        <input type="password" id="password" v-model="password" />
      </div>
      <button type="submit">login</button>
    </form>
  </section>
</template>

<script>
export default {
  middleware: 'logined_admin_user',
  data () {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    async submit () {
      await this.$store.dispatch('auth/login', {
        email: this.email,
        password: this.password
      })
      this.$router.push('/admin')
    }
  }
}
</script>

storeにはdispatchというイベントを通知する仕組みがあり、actionで定義されているイベントが通知されると、データを操作する処理が実行されます。

今回はログインのイベントを通知し、入力されたメールアドレスとパスワードが正しければ、storeに管理者ユーザーの情報が保存され、ログイン後の画面が表示されます。

アプリを起動して動作を確認する

ここまで実装ができたら、最初に定義した以下の要件が満たせているか確認していきます。

● ユーザー登録機能は実装せず、事前に用意した管理者ユーザーでログインできる
● /adminにアクセスした際にログインしていない場合は、ログイン画面に遷移する

まず、下記コマンドでLaravel(API)サーバーを起動します。

php artisan serve

次に以下のコマンドでNuxtアプリを起動します。

yarn run dev

起動が完了したら、http://localhost:3000/adminにアクセスします。

まだスタイルを反映していないので簡素ですが、上記のような画面が表示されればOKです。

次に事前に登録した管理者ユーザーのメールアドレスとパスワードを入力してloginをクリックします。

以下のような画面が表示されればOKです。

http://localhost:3000/admin/loginにアクセスしたら、
ログイン中なので、/adminにリダイレクトされることも確認しておきましょう。

次にログアウトさせたいので、
以下のようにブラウザの開発者ツールからCookieを削除します。

これで再度アクセスすると、ログイン画面が表示されればOKです。

おわりに

今回はCookieを使ったAPI経由でのユーザー認証機能の実装を行いました。
同様の流れで一般ユーザーと管理者ユーザーそれぞれに認証機能を用意することが出来ますね。

管理画面に最低限必要になるCRUD機能の実装はこちらの記事で解説しています。

DEHAソリューションズではPHPに強いエンジニアが多数在籍しています。エンジニアを1から採用するよりも、効率的で低コストで、エンジニアのスポット派遣や開発サポートもおこなっています。Laravelの環境構築を行いたい方や、PHPエンジニアの採用をしたい方はぜひお問い合わせください。


国内エンジニアは高いし、開発を遅らせたくない。
そんなあなたへ dehaソリューションズではオフショア開発によって低コストで迅速な開発をサポートしています。
数多くの案件を開発してきたdehaへの開発相談や無料お見積り相談はこちらから!

dehaソリューションへの簡単見積もりの依頼はこちら

Mai Tran

Recent Posts

クラウド型とオンプレミス型の生成AIチャットボットの違い

近年、企業のデジタルトランスフォーメーション(DX)が加速する中で、生成AIチャットボットの導入は急速に広がりを見せています。 顧客対応の自動化や業務効率化、さらには新たなユーザー体験の創出といった観点から、多くの企業がその活用に注目しています。 しかし、いざ導入を検討する段階になると、多くの企業が直面するのが「どのような形態で導入すべきか」という課題です。 この記事では、まず生成AIチャットボットの基本構造と進化の背景を整理した上で、クラウド型とオンプレミス型それぞれの特徴やメリット・デメリットを詳しく解説します。 AIチャットボットに興味がある方 クラウド型とオンプレミス型の生成AIチャットボットについて知りたい方 これらに当てはまる方におすすめの記事となっています。これを読めばクラウド型とオンプレミス型の生成AIチャットボットの違いがわかるのはもちろん、企業がどのような観点で最適な方式を選択すべきか、さらに今後の技術動向もわかりますよ。 生成AIチャットボットの基本構造と進化背景 生成AIチャットボットは、近年のAI技術の進化により急速に普及しているシステムの一つであり、自然言語処理技術を基盤として人間と自然な対話を行うことが可能なソフトウェアです。 従来のチャットボットは、あらかじめ用意されたシナリオやルールベースで動作するものが主流でありましたが、生成AIの登場により、文脈理解や柔軟な応答生成が可能となり、顧客対応や業務支援の質が飛躍的に向上しました。 生成AIチャットボットの内部構造は、大きく分けて「言語モデル」「インターフェース」「データ管理基盤」の三要素から成り立っています。 言語モデルはユーザーの入力を理解し、適切な応答を生成する役割を担います。 インターフェースはユーザーとの接点であり、Webやアプリ、業務システムなどと連携しています。 データ管理基盤は、ログやナレッジ、学習データなどを保持し、AIの精度向上に寄与します。 こうした構造を支えるインフラとして、近年特に注目されているのが「クラウド型」と「オンプレミス型」という二つの提供形態です。…

3 days ago

【2025-2026最新】オフショア市場の変化と契約形態の新たなスタンダード

近年、IT業界における開発体制は大きな転換期を迎えています。 特にオフショア開発は、かつての「コスト削減のための外注」という位置づけから、企業の開発戦略を支える重要な仕組みへと進化しているのです。 2025年の市場動向を見ると、オフショア開発の目的や契約形態、案件規模、発注先国など、さまざまな要素に変化が見られます。 この記事では、2024年と2025年の調査データをもとに、オフショア開発市場の変化を整理しながら、2026年以降のオフショア開発の新たなスタンダードについて解説します。 オフショア開発が興味がある方 開発効率を上げたい方 社内のIT人材が不足している方 これらに当てはまる方におすすめの記事となっています。これを読めば、企業がこれからオフショア開発を導入・拡大していくうえで、どのようなポイントを押さえるべきかを明らかになりますよ。 オフショア開発市場の変化 ― コスト削減から戦略的活用へ オフショア開発は長らく「開発コストを削減するための手段」として利用されてきました。 しかし近年、その役割は大きく変化しています。 2025年の市場動向を見ると、企業がオフショア開発を検討する理由は、単純なコスト削減ではなく「開発リソースの確保」や「開発スピードの向上」へとシフトしています。 これは、日本国内で慢性的なエンジニア不足が続いていることが大きな要因です。…

1 week ago

コストと品質のベストバランスはどこか?今、最も「安定」しているオフショア拠点

オフショア開発は、かつては「開発コストを下げるための手段」として利用されるケースが多く見られました。 国内エンジニアの人件費が高騰する中、海外のエンジニアリソースを活用することでコスト削減を実現するというシンプルな目的が中心だったのです。 しかし近年では、オフショア開発の位置づけは大きく変化しています。 この記事ではそんなオフショア開発の変化に着目し、オフショア開発のコストと品質のベストバランスについて紐解きます。 オフショア開発に興味がある方 オフショア拠点をお探しの方 社内のIT人材が不足している方 これらに当てはまる方におすすめの記事となっています。これを読めばオフショア開発のコストと品質について、どんなバランスが良いのかがわかるのはもちろん、安定したオフショア拠点が丸わかりですよ。 オフショア開発の現在地:コスト削減だけの時代は終わった 現在のオフショア開発は、単なるコスト削減ではなく「開発リソースの確保」や「開発スピードの向上」「グローバル開発体制の構築」など、より戦略的な目的で導入されるケースが増えています。 IT人材不足が深刻化する日本において、国内だけでエンジニアを確保することが難しくなっているため、海外人材の活用は企業にとって重要な選択肢となっています。 特に中小企業の間では、オフショア開発の活用が再び拡大しています。かつては大規模なシステム開発案件を中心に利用される傾向がありましたが、近年では中規模のプロジェクトやスモールスタート型の導入が増えています。 まずは小さな開発チームからスタートし、プロジェクトの進行に合わせてチームを拡張するという柔軟な運用が主流になりつつあります。 また、開発案件の内容も変化しています。業務系Webシステム開発は依然として主流ですが、近年はAI関連開発や高度な技術領域の案件も増えており、オフショア開発の技術レベルは着実に向上しています。 単純なコーディング作業だけでなく、設計や高度な開発工程を担うケースも珍しくなくなっています。…

2 weeks ago

【オフショア開発の価格高騰】各国の最新コスト動向と今後の展望

近年、IT開発の現場では「オフショア開発のコストが上昇している」という声が多く聞かれるようになりました。 かつてオフショア開発は「低コストで開発できる手段」として広く活用されてきましたが、現在ではその前提が変化しつつあります。 為替環境の変化、各国の人件費上昇、グローバル市場の競争激化などにより、オフショア開発の価格構造は大きく変わり始めています。 一方で、日本国内ではエンジニア不足が深刻化しており、企業は開発リソースを確保するために海外人材の活用を続けざるを得ない状況にあります。 つまり、オフショア開発は「安いから使う」ものから、「必要だから使う」ものへと役割が変化しているのです。 この記事では、オフショア開発の最新動向をもとに、各国のコスト動向、企業の発注傾向、案件内容の変化、契約形態の変化、そして今後の展望について詳しく解説します。 オフショア開発を検討している方 開発効率を上げたい方 社内のIT人材が不足している方 これらに当てはまる方におすすめの記事となっています。これを読めばオフショア開発のコスト面について最新の情報がわかるのはもちろん、今後の展望もわかりますよ。 (more…)

3 weeks ago

【不動産DX】不動産業界に最適なオークション形式とシステム選定のポイント

不動産業界は、これまで「対面営業」「紙契約」「属人的な価格交渉」といったアナログな手法が中心でした。 しかし近年、デジタル技術の進化と顧客行動の変化により、業界全体でDX(デジタルトランスフォーメーション)が加速しています。 この記事ではそんな不動産業界のDX化において、注目されている「オークション形式」についてどんな特徴があるのかや、システムを選定する際のポイントについて見ていきたいと思います。 DX化をすすめたい企業の方 不動産業界の方 社内のIT人材が不足している方 これらに当てはまる方におすすめの記事となっています。これを読めば不動産業界におけるオークション形式のポイントや注意点が丸わかりですよ。 不動産DXが求められる背景とオークションモデルの可能性 国土交通省の電子契約解禁やオンライン重要事項説明の普及により、売買・賃貸のプロセスは大きく変わりました。さらに、ポータルサイト依存型の集客モデルから脱却し、より収益性の高い販売手法を模索する動きが強まっています。 そこで注目されているのが「オークション形式」です。 従来の不動産取引は「売主が価格を提示し、買主が交渉する」という相対交渉モデルが一般的でした。 しかし、オークションモデルでは市場原理をより明確に反映させることが可能です。需要が集中するエリアや希少物件では価格が自然に上昇し、売主にとっては最大利益を得られる可能性があります。 また、オークション形式は透明性の向上にも寄与します。 価格決定のプロセスが明確になり、「なぜこの価格になったのか」という説明責任を果たしやすくなります。 これはコンプライアンス強化が求められる現代において大きな利点です。…

4 weeks ago

2026年のAIエージェント トレンド【Googleの調査】

2026年、AI活用は新たなフェーズへと突入します。これまでの「生成AIを使う」段階から、「AIエージェントが業務を遂行する」段階へと進化しています。 Google Cloudが発表したレポート『AI agent trends 2026』では、企業活動におけるAIの中心がAgentic AI(エージェント型AI)へ移行すると指摘しています。 AIエージェントとは、単に質問に答える存在ではありません。目標を理解し、計画を立て、複数のシステムを横断しながら実行まで行う「行動するAI」です。 この記事では、Googleの調査をもとに、2026年を形づくる5つのAIエージェントトレンドを詳しく解説します。 AIエージェントは何か知りたい方 業務効率を上げたい方 これらに当てはまる方におすすめの数となっています。これを読めばAIエージェントのトレンドがわかるのはもちろん、利用のポイントもわかりますよ。 すべての従業員にAIエージェントがつく時代(Agents for Every…

4 weeks ago