Saltar al contenido

Etiqueta: authentication

Autenticación en Angular con JWT

Hola, aprovechando un poco el paro que estamos teniendo en Perú por un aislamiento que a decretado el estado me di un tiempo entre el trabajo remoto y otras responsabilidades para hacer una pequeña demo sobre el uso de autenticación en Angular, específicamente como podemos valernos de interceptores y guards para poder trabajar con json web tokens (JWT).

Hago la demo de este punto en especifico por que recibi un par de preguntas la semana pasada sobre este tema y me di cuenta que en su momento para mi también entender ciertos conceptos y como se usaban me costo un poco y decidí hacer una demo y un post sobre esto.

Para explicar un poco como he decidido dividir la demo, el proyecto en angular se ha desarrollado desde 0, valiéndome de angular cli para generar la estructura básica de angular y sobre esta cree dos componentes una publico y otro protegido además de otras carpetas para los intercetores, guard y servicios. Del lado del backend, para generar nuestros JWT me estoy valiendo de una aplicación que ya tengo realizada y sólo he modificado el endpoint para generar el token y retornarlo. Veamos con más detalle nuestra aplicación en angular.

Estructura del proyecto en angular

Veamos que tenemos en nuestro «app.module»:

Configuración en AppModule
  • declarations: Se declaran los dos componentes que vamos a usar en nuestra demo el público y el privado.
  • imports: Importamos «HttpClientModule» para poder realizar conexiones http, «FormsModule» y «ReactiveFormsModule» para poder crear nuestro formulario de login. Los otros dos imports se añaden automaticamente al generar el proyecto.
  • providers: Acá estamos registrando nuestro servicio de autenticación y además registramos nuestros interceptor.

Ahora revisemos el «app-routing.module.ts»:

Configuración del AppRoutingModule

Lo único que debe importarnos acá es el registro de los routes, como podemos ver tenemos un array con dos objetos uno de ellos es nuestro componente público al cual estamos direccionando la ruta por defecto y el otro objeto es para nuestra componente protegido, en el cual es necesario indicar que para activarse (canActivate) se usará nuestro guard que se detallará más adelante.

Rapidamente, revisemos los componentes que se han creado:

Public

Configuración en el componente public
Configuración de la vista del componente public

Veamos un que tenemos en este componente. Declaramos un formulario de login típico que al realizar el submit llama al método «onSubmit()», tenemos la inidicalización de nuestro formulario y en el submit se valida si se ingresaron valores de usuario y contraseña y de ser esto así llama al servicio de login. Si este último llamado es correcto nos subscribimos a la respuesta para poder guardar el token en el localstorage y hacemos un navigate con el route a nuestro componente protegido «protected».

Protected

Configuración del componente protected

Este componente es literalmente un «ng g c protected». Dado que la demo se centra en llegar a el, no en lo que este nos va a mostrar. Veamos que sucede cuando en nuestro componente public se ejecuta la linea:

this.router$.navigate(['/protected']);

Se vemos el código, esta linea se ejecuta si y sólo si la petición que se realizo al backend por el token fue correcta y antes de realizarse se graba este token en el localstorage del browser. Cuando se ejecute, es donde entra a tallar nuestro guard. Veamos que lógica se tiene ahí.

Configuración del guard

Lo que tenemos acá es una clase creada por notros que implemente «CanActivate» y en esta implementación lo que yo estoy haciendo es intentando obtener el token que se debío grabar si la autenticación es correcta, si se obtuviera entonces retorno true y esto hace que angular nos redirija a nuestra url solicitada. De no ser asi, le estoy indicando que envíe al usuario a la ruta básica (public para nuestro caso) y que retorne false.

Revisemos para finalizar el consumo del servicio de autenticación y el interceptor.

Servicio de autenticación

Lo interesante acá es el interceptor ya se explico donde debemos registrarlo, ahora veamos como se ha implementado y que nos permite realizar.

Implementación interceptor parte I
Implementación interceptor parte II

Veamos como en el constructor de nuestro interceptor nos subscribimos a los cambios en el route, se valida el tipo de evento y luego se le indica que siga avanzando y termina entrando en nuestro método implementado «intercept» en este método validamos la url que se intenta consumir con una expresión regular, luego de verifica si existiera un token en nuestro localstorage, de ser este es el caso se clona el request inicial y se le añade el header de «Authorization» con el bearer que corresponde. Del mismo modo, se añade el header del «Content-Type» y por úlitmo siempre se añade el header del formato de la data esperada con el «Accept». Además, incrementamos los request pendiente de realizar con el «pendingRequests» y finalmente en el return le hacemos un pipe al observable que va a retornar de la solicitud. Cuando esta solicitud sea exitosa entrará a nuestra subscripción en nuestro componente que ya revisamos previamente, en el caso contrario entrará al «catcherror» y acá simplemente haremos un throwerror. Consideremos que siempre entrará al método «finalize» y es acá donde reducimos nuestras request pendientes por que ya se realizo.

Ya para terminar con este post – ahora si de verdad – veamos que hace nuestro backend.

Backend para generar el JWT

Como se puede observar, se a modificado un poco el funcionamiento del método para que basicamente reciba un usuario y contraseña, genere un token y lo retorne.

Con esto terminamos la demo y aunque el post salio un poco más extenso de lo que hubiera querido, me parece que se cubre todo a detalle. El funcionamiento de la demo pueden revisarla el video que adjunto y como siempre dejo también acceso al repositorio donde pueden encontrar el código fuente del frontend.

REPO: GITHUB

Saludos.

2 comentarios