Hola amigos, bienvenidos a este nuevo espacio que he desarrollado para poder compartir contenido de programación e ingeniería de software 100% en español y que, con el favor de Dios, comience a ser referente en el mundo de habla hispana.
Antes que nada me presento, mi nombre es Marco Ramírez, soy un ingeniero de software con casi 15 años de experiencia (a la fecha de publicación de este post) y he trabajado como desarrollador frontend web, mobile, backend y también levantando uno que otro servidor, ya sea VPS o Bare Metal (como dice la chaviza). Igualmente mi especialidad es trabajar con los siguientes lenguajes de programación:
- PHP
- Javascript
- Kotlin
- Swift
- C#
- Dart
- Java
Tengo en mi haber diversas aplicaciones desarrolladas y puestas en producción y a la vez he colaborado con diversas empresas a nivel internacional y colaborado con clientes nacionales de diversos ámbitos de la industria de estacionamientos y del sector financiero.
Dicho lo anterior, pasemos con lo que de verdad nos interesa.
Verán, al trabajar en este caso con PHP, en específico con Laravel, nos encontramos en ocasiones que deseamos tener el clásico comportamiento de autenticación de nuestras REST APIs, por lo que para ello tenemos dos alternativas: Passport y Sanctum. Passport es una librería que provee de un servidor OAUTH2 para poder realizar este trabajo. Passport hace una implementación del mismo en minutos y con la que podemos contar con tokens JWT para poder acceder a endpoints restringidos en nuestra API.
Ahora bien, Laravel, desde la versión 7, integró una nueva librería para autenticación más liviana que Passport y que a la vez puede generar múltiples tokens para los diferentes dispositivos que acceden a la API. Ahora bien, eso no quiere decir que Passport no lo haga, sin embargo, la pregunta del millón de dólares sería la siguiente:
¿Tu proceso de negocio requiere OAUTH2?
Si tu respuesta es sí, usa Passport, si no, puedes decantarte por Sanctum, que en mi opinión es más económico, en cuanto a uso de recursos del sistema se refiere y a que en este caso, las tokens generadas por Sanctum son más duraderas (hasta años) y pueden ser revocadas manualmente. La desventaja que le veo a Sanctum es que como tal, no puedes renovar token alguna, pero esa no es como tal la intención de Sanctum, misma que sí es de Passport el refrescar una token.
Si estás en el caso de uso de que no necesitas OAUTH2 o simplemente quieres cambiarte a Sanctum proveniente de Passport, entonces este post es para ti, te contaré el cómo migrarte de Passport a Sanctum en poco tiempo y poder así tener un proceso más eficiente en cuanto a autenticación se refiere.
ATENCIÓN
Migrar de Passport a Sanctum es un proceso que debes pensar muy bien y más si es que tienes muchísimos usuarios registrados en tu aplicación, puesto que el realizar dicha migración involucraría, en el caso más extremo, el solicitar a todos y cada uno de los usuarios registrados que vuelvan a ingresar una nueva contraseña, así que como decimos en México “tantéale el agua a los camotes”
Pasos para migrar
Primeramente, debemos instalar Sanctum, esto lo hacemos con la siguiente línea:
composer require laravel/sanctum
Posterior a eso, ejecuta la siguiente línea en tu terminal:php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Esto publicará los archivos de configuración de Sanctum a nuestra carpeta config. Esto incluye archivos de migración para la base de datos por lo que necesitas ejecutar:php artisan migrate
Una vez realizada la instalación, es momento de manipular lo siguiente:
Ve al archivo config/auth.php y cambia la guard que desees tener bajo Sanctum, por lo general es la de API la que queremos tener tokenizada, por lo que tendrás:'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
Cambia passport por sanctum.
Ahora, pasa hacia la clase User, esta se encuentra dentro de tu carpeta app/models. Busca esta línea:
use Laravel\Passport\HasApiTokens;
y cámbiala por esta:
use Laravel\Sanctum\HasApiTokens;
Con esto bastará en la parte de nuestro modelo, pero es hora de meternos al servicio donde generamos el login y el registro. Comencemos con el login. Si tienes un método como el siguiente:
private function getAuthAndRefreshToken($request, $email, $password) {
$oClient = OClient::where('password_client', 1)->first();
$request->request->add([
'grant_type' => 'password',
'client_id' => $oClient->id,
'client_secret' => $oClient->secret,
'username' => $email,
'password' => $password,
'scope' => '*',
]);
$response = Route::dispatch(Request::create('oauth/token', 'POST'));
$result = json_decode((string) $response->getContent(), true);
$result['success'] = !isset($result['error']);
return $result;
}
Entonces tenemos que hacer un refactor. Primero cambia de getAuthAndRefreshToken a getToken, posteriormente cambia los parámetros que recibirás a $email, $password y $deviceID. El código en su interior se va, quedando primeramente así:
private function getToken($email, $password, $deviceID)
{
}
Ingresa esta línea de código dentro del método:
$user = User::where('email', $email)->first();
Esto nos buscará el usuario con el correo electrónico que el usuario nos solicita. Si encuentra el usuario, proseguimos, en caso contrario, se regresa una respuesta de tipo 401 o 403 para denegar el acceso. Esto a la vez lo hacemos con este condicional:if (null !== $user || !Hash::check($password, $user->password)) {
return ['success' => false, 'message' => 'Correo electrónico o contraseña incorrectas'];
}
Además de checar de que el usuario que buscamos existe, confirmamos que la contraseña es correcta entregando el password que nos da el usuario y confirmando que los hashes coincidan.
En caso que la validación sea correcta, podemos regresar la token sin problemas de esta forma:
return [
'success' => true,
'access_token' => $user->createToken($deviceID)->plainTextToken
];
Con esto bastará para el login y para el registro, ahora bien, en los métodos que utilices para el controlador del login y del registro, cuida de sustituir la línea:$result = $this->getTokenAndRefreshToken(request(), request('email'), request('password'));
Por esta otra:
$result = $this->getToken($user->email, $password, $request->device_id);
Prueba ahora tu implementación, si te entrega un objeto similar al siguiente:
{
"success": true,
"access_token": "1|1QjmwWuwL3EocZcErFPw0RoBLYBT6mO9GNblOVVHd1f0ed6a"
}
La migración fue completada con éxito. Ahora es tiempo de hacer limpieza. Dentro de tu implementación, puedes eliminar lo siguiente:
- Las tablas que comienzan con OAUTH en la base de datos.
- Cualquier referencia a Passport que encuentres en tu código.
- Si hiciste la implementación de un middleware denominado CheckClientCredentials, elimínalo.
- En el archivo app/Http/Kernel.php, elimina esta línea (solo aplica si implementaste el CheckClientCredentials):
'CheckClientCredentials' => \App\Http\Middleware\CheckClientCredentials::class,
- Elimina del composer.json las líneas referentes a Passport.
- Ejecuta
composer update
.
Ya con esto, puedes implementar esta autenticación como de costumbre.
Ya para terminar, debo mencionarte que las tokens generadas por Sanctum, se utilizan como tokens BEARER, por lo que estas las entregas a tu request, por medio de la cabecera Authorization de esta manera:Authorization: Bearer <token generada>
Para cada lenguaje y aplicación es diferente, por lo que dejo a tu criterio cómo la debes implementar en el frontend. Pues bien, espero que les haya gustado este post y procuraré tenerles muchos más posts de estos, así como migrar lo mejor que he escrito de DEV.TO hacia acá, igualmente, los posts que escriba aquí en The Dev Gang, los publicaré aquí para que pueda generarse mayor jugo de visitas desde diversos blogs, así como de algunas de mis redes sociales.
Happy coding!