Ограничение IP в сетях 4G - PullRequest
1 голос
/ 05 марта 2020

Я работаю над системой голосования с Laravel, я хочу, чтобы гость голосовал только один раз в день. Это нормально работает, если они находятся в сети Wifi, как вы можете себе представить, поскольку они всегда имеют один и тот же IP-адрес. Но я попробовал с моей 4G Network, и, поскольку мы меняем IP каждый раз, когда мы повторно используем 4G, это не работает. Я почти уверен, что нет никакого способа сделать это вообще, лучше всего иметь учетные записи для голосования, и только учетные записи будут допущены к голосованию. Но это не совсем то, что я хочу.

Вот то, что у меня есть сейчас, если вам нужна идея:

Миграция:

<?php

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

class CreateGuestsVotesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('guests_votes', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->ipAddress('ip');
            $table->bigInteger('candidate_id')->unsigned();
            $table->timestamp('updated_at');

            $table
                ->foreign('candidate_id')
                ->references('id')
                ->on('candidates')
                ->onDelete('cascade');
        });
    }

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

И во всем мире я сделал Guest Singleton для управления голосами:

<?php

namespace App\Library;

use App\GuestVote;

/**
 * Singleton class to manage Guest vote
 *
 * @package App\Library
 */
class Guest {

    /**
     * @var Guest
     */
    private static $instance;

    /**
     * IP of the guest
     *
     * @var string
     */
    private static $ip;

    protected function __construct()
    {
        Guest::$ip = \Request::ip();
    }

    /**
     * Singleton, retrieve only one instance
     *
     * @return Guest
     */
    public static function getInstance(): Guest
    {
        if (empty(Guest::$instance)) {
            Guest::$instance = new Guest();
        }
        return Guest::$instance;
    }

    /**
     * Guest can vote for this candidate ?
     *
     * @param \App\Candidate $candidate
     * @return bool
     */
    public function canVote($candidate)
    {
        if (!($candidate instanceof \App\Candidate)) return false;

        $guestVote = GuestVote::where([
            'ip' => Guest::$ip,
            'candidate_id' => $candidate->id
        ])
            ->select([
                'ip',
                'candidate_id',
                'updated_at'
            ])
            ->first();

        if (!$guestVote || now()->greaterThan($guestVote->updated_at->addDay(1))) return true;
        return false;
    }

    /**
     * Vote for a candidate
     *
     * @param Illuminate\Database\Eloquent\Builder|Illuminate\Database\Eloquent\Model|object|\App\Candidate|\App\Candidate[]|Illuminate\Database\Eloquent\Collection $candidateVote
     * @throws \Exception
     */
    public function vote($candidateVote)
    {
        if (!$candidateVote) return;

        $candidates = [];
        if ($candidateVote instanceof \App\Candidate) {
            $candidates[] = $candidateVote;
        } else {
            $candidates = $candidateVote;
        }

        foreach ($candidates as $candidate) {
            if (!Guest::canVote($candidate)) continue;

            $guestVote = GuestVote::firstOrNew([
                'ip' => Guest::$ip,
                'candidate_id' => $candidate->id
            ]);

            try {
                \DB::beginTransaction();

                $candidate->increment('votes');
                $guestVote->touch();

                $guestVote->save();
                $candidate->save();

                \DB::commit();
            } catch (\Exception $e) {
                \Log::error('Error while Guest was voting : ' . $e);
                \DB::rollBack();
            }
        }
    }

}

Все работает нормально, пока я не использую свою сеть 4G. Если у вас есть идеи, как мы можем ограничить даже сети 4G? Я пытался выяснить, не можем ли мы получить MA C адрес устройства, но, к сожалению, нет: (

Спасибо

...