PHP

Laravel MiddlewareミドルウェアでIP制限機能をつくろう

Laravel

 

そのままでは動作しませんが、参考までにどうぞ。

条件

クライアントIPを判別してLaravel側のログインページのアクセスを制限する機能をつくります。

  • クライアント -> CloudFront -> ELB -> Nginx(Laravel)

 

テーブルの作成

  • 機能有効化フラグを設定
    admins.is_access_control_enabled
  • 許可IPを設定
    admin_allowed_ips.allowed_ip

 

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

/**
 * Class CreateAdminsTable.
 */
class CreateAdminsTable extends Migration
{
    /**
    * Run the migrations.
    *
    * @return void
    */
    public function up()
    {
        if (!Schema::hasTable('admins')) {
            Schema::create('admins', function (Blueprint $table) {
                $table->bigIncrements('id');
                $table->string('name')->nullable();
                $table->string('subdomain');
                $table->boolean('is_access_control_enabled')->default(false)->comment('IP制限機能が有効か?')
                $table->timestamps();

                $table->unique('hostname');
            });
        }
    }

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

 

database/migrations/2021_02_19_135616_create_admin_allowed_ips.php

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

class CreateAdminAllowedIps extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    const TABLE_NAME = "admin_allowed_ips";

    public function up()
    {
        if (Schema::hasTable(self::TABLE_NAME)) {
            return;
        }
        Schema::create(self::TABLE_NAME, function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('admin_id')->unsigned();
            $table->string('allowed_ip')->comment('アクセス許可IP');
            $table->timestamps();

            $table->foreign('admin_id', 'aai_idfk_admins')
                ->references('id')
                ->on('admins')
                ->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table(self::TABLE_NAME, function (Blueprint $table) {
            $table->dropForeign('aai_idfk_admins');
        });
        Schema::drop(self::TABLE_NAME);
    }
}


 

Entity

 

app/Entities/AdminAllowedIp

namespace App\Entities;

use Illuminate\Database\Eloquent\Model;
use Prettus\Repository\Contracts\Transformable;
use Prettus\Repository\Traits\TransformableTrait;

/**
 * Class AdminAllowedIp.
 *
 * @package namespace App\Entities;
 */
class AdminAllowedIp extends Model implements Transformable
{
    use TransformableTrait;

    protected $guarded = [
        'id'
    ];

    public function admin()
    {
        return $this->belongsTo('App\Entities\Admin');
    }
}

 

Repository

 

 

app/Repositories/Admin/AdminAllowedIpInterface

namespace App\Repositories\Admin;

use App\Repositories\Traits\ResourceConstructInterface;

interface AdminAllowedIpInterface extends ResourceConstructInterface
{
    //
}

 

app/Repositories/Admin/AdminAllowedIpRepository

namespace App\Repositories\Admin;

use App\Entities\AdminAllowedIp;
use App\Repositories\Admin\AdminAllowedIpInterface;
use App\Repositories\Traits\ResourceConstructTrait;

class AdminAllowedIpRepository implements AdminAllowedIpInterface
{
    use ResourceConstructTrait;

    public function __construct(AdminAllowedIp $resource)
    {
        $this->resource = $resource;
    }
}

 

バインド

 

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
       ・・・
        $this->app->bind(
            \App\Repositories\Admin\AdminAllowedIpInterface::class,
            \App\Repositories\Admin\AdminAllowedIpRepository::class
        );
      ・・・
    }
}

 

ミドルウェアの作成

 

App\Http\Middleware\AllowedIpCheck.php
namespace App\Http\Middleware;

use Closure;

// 管理画面 IP制限ミドルウェア
class AllowedIpCheck
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        list($subdomain, $domain, $route_domain) = (explode('.', $_SERVER['HTTP_Host']));
        // get id by subdomain
        $Admin = app()->make(\App\Repositories\Admin\AdminRepository::class)->findWhere([
            'subdomain' => $subdomain,
        ]);
        if (is_null($Admin)) {
            throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException("対象の管理者が見つかりません");
        }
        // IP制限が有効か?
        if (!$admin->is_access_control_enabled) {
            return $next($request);
        }

        // AWS固有のIP格納ヘッダーの有無チェック
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            // 1番目にデバイスIP, 2番目にCloudFront IP
            list($device_ip, $cloud_front_ip) = ($_SERVER['HTTP_X_FORWARDED_FOR'] === '') ? array() : explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); // ex. 153.xxx.xxx.1, 130.176.135.157
            // 許可IPを配列で取得
            $allowed_ips = app()->make(\App\Repositories\Admin\AdminAllowedIpRepository::class)->byWhere([
                'admin_id' => $admin->id,
            ])->pluck('allowed_ip')->toArray();
            // 許可IP確認
            if (array_search($device_ip, $allowed_ips) === false) {
                throw new \Symfony\Component\HttpKernel\Exception\NotFoundHttpException("アクセスが許可されていません");
            }
        }
        return $next($request);
    }
}

 

Kernelにミドルウェアを登録

 

app/Http/Kernel.php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;
use App\Http\Middleware\UA\SetLocale;
use App\Http\Middleware\UA\ResponseJsonFormatter;

class Kernel extends HttpKernel
{

・・・

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'admin_allowed_ip_check' => \App\Http\Middleware\AllowedIpCheck::class,
    ];
}

 

Routeに設定

ログイン画面にIP制限をかけます。

 

routes/admin.php

// IP制限ミドルウェア
Route::group(['middleware' => ['admin_allowed_ip_check']], function () {
    // 認証不要
    Route::get('/', function () {
        return view('ADMIN.login.index');
    });
    Route::group(['prefix' => 'login'], function () {
        Route::get('/', function () {
            return view('ADMIN.login.index');
        })->name('ADMIN.login.index');
    });
});

・・・

 

$ composer dumpa
$ php artisan route:clear

 

Amazonおすすめ

iPad 9世代 2021年最新作

iPad 9世代出たから買い替え。安いぞ!🐱 初めてならiPad。Kindleを外で見るならiPad mini。ほとんどの人には通常のiPadをおすすめします><

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)