Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Controllo degli accessi sugli account degli utenti

Come implementare il controllo degli accessi sugli account degli utenti in un e-commerce basato sul framework PHP Laravel
Come implementare il controllo degli accessi sugli account degli utenti in un e-commerce basato sul framework PHP Laravel
Link copiato negli appunti

In questo capitolo vedremo come implementare la logica del controllo degli accessi sugli account degli utenti.

La logica è semplice: quando registriamo un nuovo utente, salviamo nel database le informazioni circa il browser in uso e la piattaforma. Successivamente ad ogni login verifichiamo che tali informazioni siano coerenti con quelle salvate durante la registrazione.

Se così non è, salviamo le nuove informazioni e inviamo una e-mail all'utente informandolo che è stato effettuato un login con un nuovo dispositivo.

Modello di dati e struttura della tabella

Per iniziare, definiamo un nuovo modello di dati per registrare gli accessi.

php artisan make:model Access --migration

La struttura della tabella avrà come dati rilevanti l'ID dell'utente e la stringa con le informazioni sul browser.

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAccessesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('accesses', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
            $table->bigInteger('customer_id');
            $table->text('browser');
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('accesses');
    }
}

Quindi definiamo il modello per questa tabella.

namespace App;
use Illuminate\Database\Eloquent\Model;
class Access extends Model
{
    protected $table = 'accesses';
    protected $primaryKey = 'id';
    public $incrementing = true;
    protected $fillable = ['customer_id', 'browser'];
}

A questo punto creiamo il legame one-to-many nel modello dell'utente.

public function accesses()
    {
        return $this->hasMany('App\Access');
    }

Ottenere le informazioni sul device

Abbiamo bisogno di ottenere le informazioni sul device dell'utente. Per far questo dobbiamo installare il package Agent e includerlo nella nostra applicazione come viene spiegato nell'articolo che abbiamo linkato.

Quindi nel nostro controller AJAX dobbiamo salvare inizialmente le informazioni di accesso quando l'utente viene registrato.

agent = new Agent();
$browser = $agent->browser();
$version = $agent->version($browser);
$platform = $agent->platform();
$browser_str = $browser . ' ' . $version . ' ' . $platform;
 $access_data = [
         'customer_id' =>  $customer->id,
            'browser' => $browser_str
        ];
$access = new Access($access_data);
$access->save();

La stringa browser contiene il nome del browser, la versione e la piattaforma in uso. A scopo di logging si potrebbe anche scegliere di salvare l'IP dell'utente, ma per il nostro esempio è sufficiente memorizzare solo queste informazioni.

Classe Mailable e logica DRY

Ora dobbiamo creare una classe di tipo Mailable che gestirà l'invio dell'e-mail di notifica all'utente.

namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class AccessEmail extends Mailable
{
    use Queueable, SerializesModels;
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct( $browser )
    {
        $this->browser = $browser;
    }
    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return
            $this->from('phpecommerce@localhost')->
            subject('New login')->
            view('email.access', [
                'browser' => $this->browser
            ]);
    }
}

Il template Blade per questa e-mail usa solo la variabile browser che viene mostrata all'utente in questo modo:

<p>Dear customer,<br>
    we have detected a new login from an unknown browser.</p>
<p>Browser: {{ $browser }}</p>

La logica della verifica su ogni login è divisa in due fasi. Nella prima, acquisiamo i dati del browser dalla richiesta HTTP. Nella seconda, effettuiamo una verifica dell'esistenza di tali dati associati all'utente corrente. Se i dati non esistono, e quindi siamo di fronte ad un nuovo browser, passiamo a registrare i nuovi dati e inviamo l'e-mail di notifica all'utente.

Poiché vogliamo seguire la logica DRY (Don't Repeat Yourself) in un caso in cui la routine è abbastanza complessa, definiamo un metodo protected nel nostro controller che implementerà questa logica accettando come unico parametro l'istanza del modello dell'utente.

protected function accessControl($customer)
    {
        $agent = new Agent();
        $browser = $agent->browser();
        $version = $agent->version($browser);
        $platform = $agent->platform();
        $browser_str = $browser . ' ' . $version . ' ' . $platform;
        if(!Access::where([['customer_id', '=', $customer->id], ['browser', '=', $browser_str]])->exists()) {
            $access_data = [
                'customer_id' =>  $customer->id,
                'browser' => $browser_str
            ];
            $access = new Access($access_data);
            $access->save();
            Mail::to($customer->email)->send(new AccessEmail($browser_str));
        }
    }

Il metodo exists() è da preferire al metodo get() seguito da una verifica sull'eguaglianza a null, perché questo metodo non solo ci risparmia un passaggio ma evita anche di reperire comunque un record se questo non esiste nel database.

Quindi tale metodo può essere invocato nel metodo che gestisce il login prima di restituire una risposta al client.

$this->accessControl($customer);
        return response()->json(['success' => true, 'from_checkout' => $from_checkout]);

L'unico svantaggio dell'implementare il controllo degli accessi ad ogni login è che l'utente potrebbe percepire un minimo ritardo nel redirect sul suo profilo. Tuttavia se si considera che l'invio della notifica ha luogo solo nel caso in cui ci troviamo di fronte ad un nuovo browser, possiamo dire che non avverrà con troppa frequenza.

Conclusione

Il controllo degli accessi è un livello di protezione aggiuntivo per gli account degli utenti. Nel prossimo capitolo vedremo come aggiungere un ulteriore livello di sicurezza implementando l'autenticazione a due fattori.

Ti consigliamo anche