そのままでは動作しませんが、参考までにどうぞ。
もくじ
条件
クライアント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