Laravel: 등록 또는 로그인 후 사용자 IP를 추적하는 방법

영감



계획은 사용자 테이블에 새 열을 생성하여 사용자가 가입한 소스 국가로 사용자 국가 코드를 저장하고 매일 또는 사용자가 시스템에 로그인할 때마다 사용자 IP 주소의 기록을 저장하는 테이블을 만드는 것입니다. .

정보를 트리거하고 저장하는 2개의 이벤트가 있습니다.
  • 사용자 등록 후
  • 사용자 로그인 후 및 사용자가 일반 사용자의 백엔드를 방문할 때(페이지에 액세스할 때 너무 많은 작업에 캐싱)

  • 연구



    이제 이 작업을 수행하는 데 도움이 되는 라이브러리를 찾아야 합니다 😎. 왜냐하면 저는 게으른 사람이기 때문입니다. 미리 준비하고 생산성을 높이고 싶습니다.

    google.com 및 github.com을 검색한 다음 도움이 되는 라이브러리를 거의 찾지 못했습니다. 그러나 나는 이것이 깨끗하고 마지막 커밋을 불과 19일 전에 보았는데 이는 제작자의 좋은 지원을 의미합니다.

    https://github.com/stevebauman/location



    갑시다



    1. 놀아요




    composer require stevebauman/location
    


    데이터를 자세히 살펴보기 전에 먼저 데이터를 테스트할 경로를 만듭니다.

    use Stevebauman\Location\Facades\Location;
    
    Route::get('/_t', function () {
        if ($position = Location::get()) {
            // Successfully retrieved position.
            return $position;
        } else {
            // Failed retrieving position.
            return ':(';
        }
    })->name('test');
    


    결과:

    {
      "ip": "66.102.0.0",
      "countryName": "United States",
      "countryCode": "US",
      "regionCode": "CA",
      "regionName": "California",
      "cityName": "Mountain View",
      "zipCode": "94043",
      "isoCode": null,
      "postalCode": null,
      "latitude": "37.422",
      "longitude": "-122.084",
      "metroCode": null,
      "areaCode": "CA",
      "timezone": "America/Los_Angeles",
      "driver": "Stevebauman\\Location\\Drivers\\IpApi"
    }
    


    보시다시피 위의 데이터를 기반으로 Laravel 프로젝트에서 마이그레이션을 생성합니다.

    2. 마이그레이션



    사용자 테이블에 country_code 열 생성

    php artisan make:migration add_country_code_column_to_users_table
    



    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    class AddCountryCodeColumnToUsersTable extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::table('users', function (Blueprint $table) {
                $table->string('country_code')->nullable()->index();
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::table('users', function (Blueprint $table) {
                $table->dropColumn('country_code');
            });
        }
    }
    


    사용자 IP 주소를 저장할 히스토리 테이블 생성

    php artisan make:model UserIpAddress -m
    



    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    class CreateUserIpAddressesTable extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('user_ip_addresses', function (Blueprint $table) {
                $table->id();
                $table->string('ip')->index(); // "66.102.0.0",
                $table->string("countryName")->nullable(); // "United States",
                $table->string("countryCode")->nullable(); // "US",
                $table->string("regionCode")->nullable(); // "CA",
                $table->string("regionName")->nullable(); // "California",
                $table->string("cityName")->nullable(); // "Mountain View",
                $table->string("zipCode")->nullable(); // "94043",
                $table->string("isoCode")->nullable(); // null,
                $table->string("postalCode")->nullable(); // null,
                $table->string("latitude")->nullable(); // "37.422",
                $table->string("longitude")->nullable(); // "-122.084",
                $table->string("metroCode")->nullable(); // null,
                $table->string("areaCode")->nullable(); // "CA",
                $table->string("timezone")->nullable(); // "America/Los_Angeles",
                $table->char('user_id', 26)->index();
                $table->timestamps();
    
                $table->index(['ip', 'user_id']);
            });
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
            Schema::dropIfExists('user_ip_addresses');
        }
    }
    



    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Factories\HasFactory;
    use Illuminate\Database\Eloquent\Model;
    
    class UserIpAddress extends Model
    {
        use HasFactory;
    
        protected $guarded = [];
    
        public function parseData($data)
        {
            $payload = [];
    
            $payload["countryName"] = $data["countryName"] ?? false;
            $payload["countryCode"] = $data["countryCode"] ?? false;
            $payload["regionCode"] = $data["regionCode"] ?? false;
            $payload["regionName"] = $data["regionName"] ?? false;
            $payload["cityName"] = $data["cityName"] ?? false;
            $payload["zipCode"] = $data["zipCode"] ?? false;
            $payload["isoCode"] = $data["isoCode"] ?? false;
            $payload["postalCode"] = $data["postalCode"] ?? false;
            $payload["latitude"] = $data["latitude"] ?? false;
            $payload["longitude"] = $data["longitude"] ?? false;
            $payload["metroCode"] = $data["metroCode"] ?? false;
            $payload["areaCode"] = $data["areaCode"] ?? false;
            $payload["timezone"] = $data["timezone"] ?? false;
    
            return $payload;
        }
    }
    


    3. 라라벨 이벤트로 정보 저장하기



    몇 년 후, 나는 Laravel과 함께 일하고 있습니다. 대기열과 특히 Laravel Horizon이 태스크와 작업을 동시에 병렬로 처리할 때 매우 강력하다는 점이 마음에 들었습니다.

    Laravel Queue에 대한 경험이 없는 경우. Laravel 스택으로 작업할 때 실수입니다 🌝

    그래서 우리는 Laravel Events으로 들어갑니다. 나는 Laravel 문서를 좋아합니다. 그들은 그것을 매우 유용하고 깨끗하고 명확하게 만들었습니다. 🎉

    조사한 후 Illuminate\Auth\Events\Registered , Illuminate\Auth\Events\Login 이라는 2개의 이벤트를 사용할 수 있음을 발견했습니다. app/Providers/EventServiceProvider.php 파일에서 확인하실 수 있습니다.

    <?php
    
    namespace App\Providers;
    
    use Illuminate\Auth\Events\Registered;
    use Illuminate\Auth\Events\Login;
    use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
    use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
    use Illuminate\Support\Facades\Event;
    
    class EventServiceProvider extends ServiceProvider
    {
        /**
         * The event listener mappings for the application.
         *
         * @var array
         */
        protected $listen = [
            Registered::class => [
    
            ],
            Login::class => [
    
            ]
        ];
    
        /**
         * Register any events for your application.
         *
         * @return void
         */
        public function boot()
        {
    
        }
    }
    


    이제 코드를 트리거하고 정보를 저장하기 위해 해당 이벤트를 수신하는 2개의 리스너를 생성합니다.

    Laravel 이벤트 문서를 읽고 리스너를 만드는 방법을 알아봅시다.

    php artisan make:listener LogUserIpAddressLoginListener
    php artisan make:listener LogUserIpAddressRegisteredListener
    



    <?php
    
    namespace App\Listeners;
    
    use App\Models\UserIpAddress;
    use Illuminate\Auth\Events\Login;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Queue\InteractsWithQueue;
    use Stevebauman\Location\Facades\Location;
    
    class LogUserIpAddressLoginListener
    {
        /**
         * Create the event listener.
         *
         * @return void
         */
        public function __construct()
        {
            //
        }
    
        /**
         * Handle the event.
         *
         * @param  \App\Events\Login  $event
         * @return void
         */
        public function handle(Login $event)
        {
            $user = $event->user;
            if ($user) {
                if ($position = Location::get()) {
                    $userIpAddress = new UserIpAddress(
                        UserIpAddress::parseData((array) $position)
                    );
                    $userIpAddress->ip = $position->ip;
                    $userIpAddress->user_id = $user->id;
                    $userIpAddress->save();
                }
            }
        }
    }
    



    <?php
    
    namespace App\Listeners;
    
    use Illuminate\Auth\Events\Registered;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Queue\InteractsWithQueue;
    use Stevebauman\Location\Facades\Location;
    
    class LogUserIpAddressRegisteredListener
    {
        /**
         * Create the event listener.
         *
         * @return void
         */
        public function __construct()
        {
            //
        }
    
        /**
         * Handle the event.
         *
         * @param  \App\Events\Registered  $event
         * @return void
         */
        public function handle(Registered $event)
        {
            $user = $event->user;
            if ($user) {
                if ($position = Location::get()) {
                    $user->country_code = $position->countryCode;
                    $user->save();
                }
            }
        }
    }
    


    그런 다음 2개의 리스너를 EventServiceProvider에 추가합니다.

    <?php
    
    namespace App\Providers;
    
    use App\Listeners\LogUserIpAddressLoginListener;
    use App\Listeners\LogUserIpAddressRegisteredListener;
    use Illuminate\Auth\Events\Registered;
    use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
    use Illuminate\Support\Facades\Event;
    use Illuminate\Auth\Events\Login;
    
    class EventServiceProvider extends ServiceProvider
    {
        /**
         * The event listener mappings for the application.
         *
         * @var array
         */
        protected $listen = [
            Registered::class => [
                LogUserIpAddressRegisteredListener::class
            ],
            Login::class => [
                LogUserIpAddressLoginListener::class
            ]
        ];
    
        /**
         * Register any events for your application.
         *
         * @return void
         */
        public function boot()
        {
    
        }
    }
    


    완료 🎉

    더 빠르고 시원하게 만들고 싶다면 대기열을 사용할 수 있습니다(트래픽이 많고 사용자가 많은 사이트의 경우 나중에 처리할 수 있고 서버에 스트레스를 주지 않기 때문입니다). 해당 리스너에 대해 Illuminate\Contracts\Queue\ShouldQueue를 구현합니다. 그래서 <3 Laravel입니다.

    결과를 즐기십시오.

    읽어주셔서 감사합니다 👋

    좋은 웹페이지 즐겨찾기