Tempo di lettura: 75 minuti
Laravel:Proteggere le API tramite il middleware JWT
Al momento, proteggiamo solo il lato client (la nostra app Angular). Questo è un grosso problema! Qualsiasi utente che conosce le nostre API può accedere e manipolare i nostri dati. Grandi rischi per la sicurezza, giusto?
Fortunatamente, possiamo facilmente evitare questi rischi dicendo a Laravel che: “Ehi, voglio che controlli le richieste degli utenti . Alcune richieste devono avere un token per accedere ai dati privati!”.
Ci sono molti modi per ottenere questo risultato, ma il modo più semplice è quello di utilizzare i middleware forniti con il pacchetto jwt-auth .
Ci sono due middleware:
- GetUserFromToken : controlla l’intestazione e la stringa di query per trovare il token e decodificalo.
- RefreshToken : ottiene un token dalla richiesta e genera un nuovo token, basato su quello vecchio. Se desideri utilizzare un token solo una volta, puoi utilizzare questo middleware.
Puoi saperne di più su questi middleware su:
https://github.com/tymondesigns/jwt-auth/wiki/Authentication
Per utilizzare questi middleware, apri app/Http/Kernel.php , aggiungi jwt.auth e jwt.refresh a $ routeMiddleware :
App Laravel – Kernel.php
protected $routeMiddleware = [ 'auth' => \Illuminate\Auth\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'cors' => \App\Http\Middleware\Cors::class, 'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken', 'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken', ];
Possiamo specificare il middleware all’interno del costruttore del nostro controller.
Ad esempio, se vogliamo proteggere tutte le rotte degli users , possiamo aprire UserController e trovare:
class UserController extends Controller {
Aggiungi sotto:
public function __construct() { $this->middleware('jwt.auth'); }
Visita http://127.0.0.1:8000/api/v1/users , dovresti vedere un errore perché devi inviare un token per accedere a questo percorso.
Se avessimo la necessità di proteggere solo alcune rotte, potremmo limitare il middleware solo a determinati metodi su una classe controller utilizzando except :
public function __construct() { $this->middleware('jwt.auth', ['except' => ['index', 'show']]); }
Angular:Invio di un token con ogni richiesta
Ora dobbiamo inviare un token dalla nostra app Angular agli endpoint API per accedere ai dati privati. Se le nostre richieste non hanno un token, non possiamo accedere ai dati. Ad esempio, visita http://localhost: 4200/admin/users , non puoi vedere nessun utente.
Nell’ultima versione di Angular, possiamo scrivere un interceptor che aggiunge un token a tutte le richieste in uscita. Tuttavia, questo è un po ‘complicato..
Fortunatamente, possiamo usare la versione più recente di angular2-jwt per risolvere facilmente il problema!
Utilizzo del pacchetto angular-jwt per inviare un token con ogni richiesta
Per fare ciò, dobbiamo installare l’ultima versione di angular2-jwt , che ora si chiama angular-jwt .
Abbiamo installato il pacchetto nella sezione precedente, quindi tutto ciò che dobbiamo fare è aprire il file app.module.ts e trovare:
allowedDomains: ['localhost:4200'],
quindi modificare in:
allowedDomains: ['localhost:4200', '127.0.0.1:8000'],
Molto bene! Qualsiasi richiesta inviata utilizzando HttpClient di Angular avrà automaticamente un token allegato come intestazione di autorizzazione.
Controlla di nuovo la nostra app! http://localhost:4200/admin/users , ora possiamo accedere ai dati privati!
Angular:Modificare la navBar
Attualmente, il nostro menu a tendina mostra sempre Registrati e Accedi . Non è del tutto corretto. Se abbiamo effettuato l’accesso, dovrebbe mostrare Logout , giusto?
Apri navbar.component.ts e aggiungi un nuovo booleano chiamato isLoggedin :
export class NavComponent implements OnInit { isLoggedIn = false;
Dopodiché, possiamo utilizzare AuthService e Router per verificare se gli utenti hanno effettuato l’accesso o meno . Aggiorna il costruttore come segue:
constructor(private auth: AuthService, router: Router) { router.events.forEach((event) => { if (event instanceof NavigationStart) { if (this.auth.loggedIn()) { this.isLoggedIn = true; } else { this.isLoggedIn = false; } } }); }
Importa AuthService , NavigationStart , Router nel componente:
import { Component, OnInit } from '@angular/core'; import {AuthService} from '../../services/auth.service'; import {NavigationStart, Router} from '@angular/router';
La cosa interessante da notare è che possiamo usare router.events per verificare se il percorso è cambiato:
router.events.forEach((event) => { if(event instanceof NavigationStart) {
Quando gli utenti si spostano su un altro percorso, controlliamo nuovamente lo stato degli utenti.
Ora possiamo usare ngIf per visualizzare un menu a discesa diverso quando gli utenti hanno effettuato l’accesso.
Apri shared/navbar.component.ts e trova:
<div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="/register">Register</a> <a class="dropdown-item" href="/login">Login</a> </div>
modifica in:
<div *ngIf="!isLoggedIn" class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="/register">Register</a> <a class="dropdown-item" href="/login">Login</a> </div> <div *ngIf="isLoggedIn" class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="/admin">Admin</a> <a class="dropdown-item" href="/logout">Logout</a> </div>
Ora prova! Se hai effettuato l’accesso, dovresti vedere un menu a discesa diverso: