Al contrario de lo que nos provee Laravel, para la gestión de autenticación usaremos un único controlador «TokenAuthController».
Este post vamos a crear lo siguiente:
- Las rutas para el formulario de inicio de sesión y su posterior procesado.
- La vista que usaremos será la que Laravel trae por defecto.
- El método/función que nos ocupa es el Login, que se encargará de:
- validar los datos que vienen del formulario.
- verificar si quiere ser recordado o no.
- localizar el usuario en la base de datos para saber si existe (si está registrado).
- emitir evento de Login.
- devolver las respuestas tanto de éxito (con el token y el usuario) como de fallo (mensaje de error).
- Crear un manejador del Evento Login que proporciona Laravel para modificar ciertos campos.
Vamos con las rutas:
1 2 3 4 5 |
Route::get('/', function () { // vista que viene por defecto en Laravel return view('auth.login'); }); Route::post('login', 'TokenAuthController@login'); |
Turno del controlador, que contendrá toda la lógica de autenticacion, registro de usuarios y demás:
1 |
php artisan make:controller TokenAuthController |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
use App\User; use Carbon\Carbon; use Illuminate\Http\Request; use Tymon\JWTAuth\Facades\JWTAuth; class TokenAuthController extends Controller { public function login(Request $request) { // validación de los datos del formulario $this->validate($request, [ 'email' => 'required|email', 'password' => 'required|min:4|max:60' ],$messages=[]); $credentials = $request->only('email', 'password'); // fecha/hora de expiración: en 5 min $expDate = Carbon::now()->addMinutes(5)->timestamp; // si el usuario marca la casilla "recuerdame/remember me" // cambiamos su fecha/hora de expiración $customClaims = $request->remember ? $customClaims = ['exp' => $expDate] : []; try { if (!$token = JWTAuth::attempt($credentials, $customClaims)) { return response()->error('invalid_credentials', 401); } } catch (JWTException $e) { return response()->error('could_not_create_token', $e->getStatusCode()); } try { // verificamos que el usuario se haya registrado previamente $user = User::where('email', $request->email)->firstOrFail(); // emitimos evento de Login event(new \Illuminate\Auth\Events\Login($user, true)); } catch (Exception $e) { return response()->error('could_not_login_user', $e->getStatusCode()); } return response()->success(compact('token','user')); } } |
Vamos a crear un manejador del evento Login (un listener) disparado en la línea 39, asociando ambos en el provider de eventos, tal que:
1 2 3 4 5 6 7 8 |
class EventServiceProvider extends ServiceProvider { protected $listen = [ 'Illuminate\Auth\Events\Login' => [ 'App\Listeners\UpdateLastLoggedAtOnLogin', ], ]; } |
Con este comando, generamos tanto el evento como su listener, pero como el evento ya existe, genera únicamente el listener:
1 |
php artisan event:generate |
Abrimos y editamos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
use Carbon\Carbon; use Illuminate\Auth\Events\Login; use Illuminate\Support\Facades\Request; class UpdateLastLoggedAtOnLogin { public function handle(Login $event) { $now = Carbon::now()->timestamp; // para que no se actualice la columna "updated_at" $event->user->timestamps = false; if (is_null($event->user->last_logged_at)) { $event->user->last_logged_at = $now; } $event->user->current_login_time = $now; $event->user->online = 1; $event->user->save(); } } |
Hay que tener en cuenta que los campos que se actualizan en el listener deben ser incluidos en la migración de la tabla «users», tal que:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { . . . . $table->boolean('online')->default(false); $table->bigInteger('current_login_time')->nullable(); $table->bigInteger('last_logged_at')->nullable(); }); } . . . . } |
1 2 3 4 |
class User extends Authenticatable implements JWTSubject { protected $hidden = [ 'current_login_time', . . . ]; } |