Saltar al contenido

Etiqueta: java

JWT en Spring Boot y Spring Security

Hace poco tiempo participe en una hackaton con unos amigos, y cuando empezamos a desarrollar ya la aplicación luego de haber analizado lo que se buscaba solucionar, yo me valí de una plantilla en spring que había estado trabajando en mi tiempo libre, era la primera ves que la ponía a prueba en un escenario real y el sentido era que ahorraramos tiempo en configurar cosas que siempre son necesarias en todos los aplicativos. Para resumir un poco esta parte, la plantilla se porto como debía. Esta experiencia me lleva a realizar este post, en el que voy a explicar como se configura spring security y la autenticación en base de datos, además de que configurar para poder usarlo con una aplicación SPA del lado del frontend, como puede ser Angular, React, Vue.js entre otras.

Como deben de saber spring security es la librería de spring que nos brinda una visión dogmática de como se debería de implementar la seguridad en una aplicativo. Esto, claro siguiente todo un marco de buenas prácticas que muy probablemente si quisiéramos implementarla de 0, tranquilamente puede ser un proyecto entero sólo para esto. Gracias a esto, es que nos permite ahorrarnos mucho tiempo y nos brinda la seguridad de que estamos siguiendo un marco de buenas prácticas. Para nuestro caso, usaremos json web token (jwt) el cual es una de las alternativas que tenemos para implementar la autenticación.

Nuestra aplicación demo consta de distintas capas, ampliamente explicadas en post anteriores, tenemos un archivo de configuración “application.yml”, en la sección “security” hemos definido cierta información importante, entre las cuales está:

  • La url del enpoint de autenticación.
  • El tiempo máximo de expiración de un token.
  • La llave secreta que se usará para poder generar el JWT.

Se ha definido un paquete de configuración, y dentro de este un paquete de jwt, en el cual se tienen distintas clases necesarias para configurar, como es obvio en el pom del archivo se están añadiendo las dependencias de spring security.

Dependencia en el POM
Clases de configuración

Tenemos un controlador llamada “SecurityController”, en el cual tenemos los diferentes endpoint:

  • Authenticate [POST]: Nos permite iniciar sesión en el sistema, retorna el token.
  • Refresh [GET]: Permite refrescar el token que se ha generado, antes de que expire.
  • Create [POST]: Permite crear un usuario.

Tenemos en la capa service de nuestro aplicativo un “SecurityService” que es donde se realiza la lógica necesaria para autenticarse, refrescar el token y el crear un nuevo usuario, Por otro lado, en el repository, respetando el principio de single responsability tenemos tres clases (Person, Session y User) para el acceso a la base de datos.

El esquema de base de datos que vamos a usar es el siguiente:

Modelo E-R usado

Vamos a usar una clase a modo de helper, donde tendremos varios métodos utilitarios que nos van a permitir obtener información del token que generemos e incluso generarlo. Esta clase se llamará “JwtUtil”.

Métodos en JwtUtil

Luego es necesario crear una clase que extienda de “OncePerRequestFilter”, en el cual podamos hacer un override al método “doFilterInternal”, en le cual haremos un filtro a las peticiones que recibamos para determinar si poseen token o no y que acciones se deberían tomar. Esta clase la llamaremos “JwtTokenAuthorizationOncePerRequestFilter” y luego veremos donde debemos configurarla para que este filtro se lleve a cabo.

Clase JwtTokenAuthorizationOncePerRequestFilter

También es necesario crear un clase que extienda de “AuthenticationEntryPoint” para poder hacer un override del método “commence”, el cual será llamado cuando se determine que ser esta intentando acceder a un endpoint que requiere que se le pase un header de authorization. Esta clase, llevará el nombre de “JwtUnAuthorizedResponseAuthenticationEntryPoint”.

Clase JwtUnAuthorizedResponseAuthenticationEntryPoint

Finalmente, toda la magia ocurre en nuestra clase SecurityConfiguration, la cual extiende de “WebSecurityConfigurerAdapter”, en esta realizamos múltiples configuraciones que son propias de spring security, Entraremos al detalle de algunas en el post, pero en el video me daré más tiempo para explicar la configuración de esta clase. Uno de los override es al método “configure”, considerando que este método en la clase de la que estamos extiendo tiene varios overloads, el que explicaré en el post es el que posee como parametro de entrada un “HttpSecurity”, en debemos realizar las siguientes configuraciones:

  • Deshabilitar el CSRF
  • Indicar que authentication entrypoint (acá usamos nuestra entrypoint personalizado).
  • Indicamos que no usaremos sesiones, esto cambiando la configuración de “sessionCreationPolicy”.
  • Configuramos el CORS, para que permita todos los tipos de peticiones (GET, POST, DELETE, UPDATE, etc).
  • Añadimos el filtro que personalizamos anteriormente, esto con el “addFilterBefore”.
Clase SecurityConfiguration

Finalmente, revisemos nuestro “SecurityController”:

SecurityController

Realizemos algunas pruebas en postman de los distintos métodos.

  • Usuario: wgutierrez
  • Contraseña: $2a$10$3zHzb.Npv1hfZbLEU5qsdOju/tk2je6W6PnNnY.c1ujWPcZh4PL6e

Petición:

Solicitud al Authenticate endpoint

Respuesta:

Respuesta el Authenticate endpoint

Como se puede ver, se nos ha generado un token, si vamos a una página como jwt.io y ponemos el token que ha sido generado, tenemos la siguiente información:

Información del token generado

Los métodos de refresh y creación, pueden verlos a más detalle en el video que como de costumbre cuelgo con los post. Espero que les haya sido de ayuda, si tienen alguna duda les dejo el correspondiente repositorio en github, y los medios de contacto correspondientes.

REPO: GITHUB

Saludos.

Deja un comentario

Grabar log de errores en db y archivo con Spring Boot

Llevo ya algunas semanas revisando cursos sobre Spring, como he mencionado en publicaciones anteriores, el trabajo me lleva a desarrollar más en tecnologías de Microsoft. Sin embargo, conforme voy aprendido más de spring, me interesa más por lo pontente que es y el beneficio que brinda al evitar la repetición de código que no le suma nada a la lógica de negocio o ”  boilerplate code “.

El post de hoy, lo centrare en el grabado de logging cuando tenemos una aplicación hecha con spring boot, como saben el log es fundamental dado que un buen log nos permite resolver los problemas de nuestro aplicativo sin mucha demora, en un post posterior explicare lineamientos para generar un buen log y buenas practicas en el mismo. Sin embargo me interesa hacer un post de esto acá porque he tenido que revisar mucho la documentación para poder configurar el log como lo necesitaba en spring y no pude encontrar ningún lugar donde expliquen detenidamente como poder realizar esto.

El log que grabaremos se realizará en base de datos (postgres) y un archivo de texto (.txt), se pueden tener multiples tipos (niveles) de log, que nos permiten medir la usabilidad de los features, los errores y las caidas fatales del sistema, para la demo me enfocare en los errores y explicare como en spring podemos capturar todos los errores que se generen, grabarlos en base de datos y el archivo de texto y al usuario mostrarle un mensaje de texto genérico y un código vinculado a nuestro registro de error.

APLICATIVO

Estoy usando Intellij IDEA como IDE para el desarrollo de esta demo, y la aplicación se divide en repository, service y controller. Considerando que el repository y service tenemos una implementación para las interfaces que definimos. Además, en repository tenemos una capa para hacer el mapping a entidades de lo recibido por la base de datos.

Project files de Spring boot

Para grabar los logs, usar log4j2 que es una librería de amplia trayectoria y bien documentada, para configurarla en la sección de resources de nuestra aplicación es necesario crear un archivo de configuración, este puede ser un xml, json o un properties. En mi caso cree un “log4j2.properties” .

Archivo de configuración del log

En el properties de spring es necesario indicarle que tenemos un archivo de configuración de log con las siguientes sentencias:

Configuración en el application.properties para el log

En el log4j2.properties que hemos creado es necesario indicar la siguiente configuración.

Configuración del log en log4j2.properties

En esta estamos indicando el indicando al configuración de la base de datos, es necesario indicar cada columna de la tabla que hemos destinado para los logs en base de datos con los valores que se van a considerar para cada columna. También está la configuración para el archvo de texto, finalmente se indica que ambos appender deben ser utilizados y el nivel mínimo del log.

También es posible indicar en el log variables configuradas por nosotros, para mi caso es necesario saber el endpoint que se está consumiendo, el nombre del método del endpoint, el nombre del método donde el error ocurrio, un guid para vincular el error a un identificador único entre otros valores. Esto podemos conseguirlo seteando variables como propiedades del sistema y luego leyendo en nuestro log4j2.propierties.

Seteo de variables como propiedades del sistema
Obtenemos la propiedad del sistema en log4j2.properties

Una explicación didáctica de esta configuración así como algunas cosas que no pongo en el post para no hacerlo muy extenso lo encuentran en el video. Quedan muchos puntos por detallar más que desarrolloraré en otros posts, espero que les haya sido de utilidad y como siempre dejo los links al repositorio para que revisen ustedes el código.

REPO: GITHUB

Saludos.

1 comentario