En este tema, aprenderemos cómo configurar Spring Security en una aplicación Spring Boot. Spring Security es un marco poderoso y altamente personalizable para la autenticación y autorización en aplicaciones Java. A lo largo de esta sección, cubriremos los conceptos básicos de la configuración de Spring Security, incluyendo la configuración de seguridad básica, la personalización de la autenticación y la autorización, y la integración con bases de datos para la gestión de usuarios.

Contenido

Configuración Básica de Spring Security

Paso 1: Añadir Dependencias

Para empezar, necesitamos añadir las dependencias de Spring Security en nuestro archivo pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Paso 2: Configuración por Defecto

Spring Boot proporciona una configuración de seguridad por defecto que protege todas las rutas de nuestra aplicación. Al añadir la dependencia de Spring Security, nuestra aplicación requerirá autenticación para todas las rutas.

Paso 3: Configuración Personalizada

Podemos personalizar la configuración de seguridad creando una clase que extienda WebSecurityConfigurerAdapter:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll() // Permitir acceso sin autenticación a rutas públicas
                .anyRequest().authenticated() // Requerir autenticación para cualquier otra ruta
                .and()
            .formLogin()
                .loginPage("/login") // Página de inicio de sesión personalizada
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Explicación del Código

  • @Configuration y @EnableWebSecurity: Anotaciones que indican que esta clase es una configuración de seguridad.
  • authorizeRequests(): Método para definir las reglas de autorización.
  • antMatchers("/public/**").permitAll(): Permite el acceso sin autenticación a cualquier ruta que comience con /public/.
  • anyRequest().authenticated(): Requiere autenticación para cualquier otra ruta.
  • formLogin(): Habilita el formulario de inicio de sesión.
  • loginPage("/login"): Especifica una página de inicio de sesión personalizada.
  • logout(): Habilita la funcionalidad de cierre de sesión.

Personalización de la Autenticación

Paso 1: Configuración de Usuarios en Memoria

Podemos configurar usuarios en memoria para propósitos de prueba:

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }
}

Explicación del Código

  • auth.inMemoryAuthentication(): Configura la autenticación en memoria.
  • withUser("user").password("{noop}password").roles("USER"): Añade un usuario con el rol USER.
  • {noop}: Indica que la contraseña no está codificada.

Personalización de la Autorización

Paso 1: Configuración de Roles y Permisos

Podemos definir roles y permisos específicos para diferentes rutas:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN") // Solo usuarios con rol ADMIN pueden acceder
            .antMatchers("/user/**").hasRole("USER") // Solo usuarios con rol USER pueden acceder
            .antMatchers("/public/**").permitAll() // Permitir acceso sin autenticación a rutas públicas
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
        .logout()
            .permitAll();
}

Explicación del Código

  • antMatchers("/admin/**").hasRole("ADMIN"): Solo usuarios con el rol ADMIN pueden acceder a rutas que comiencen con /admin/.
  • antMatchers("/user/**").hasRole("USER"): Solo usuarios con el rol USER pueden acceder a rutas que comiencen con /user/.

Integración con Bases de Datos

Paso 1: Configuración de la Fuente de Datos

Primero, configuramos la fuente de datos en application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

Paso 2: Configuración de Usuarios en la Base de Datos

Creamos una tabla de usuarios y roles en la base de datos:

CREATE TABLE users (
    username VARCHAR(50) NOT NULL PRIMARY KEY,
    password VARCHAR(100) NOT NULL,
    enabled BOOLEAN NOT NULL
);

CREATE TABLE authorities (
    username VARCHAR(50) NOT NULL,
    authority VARCHAR(50) NOT NULL,
    FOREIGN KEY (username) REFERENCES users(username)
);

Paso 3: Configuración de la Autenticación con JDBC

Configuramos la autenticación para usar JDBC:

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
            .dataSource(dataSource)
            .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?")
            .authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Explicación del Código

  • auth.jdbcAuthentication(): Configura la autenticación para usar JDBC.
  • dataSource(dataSource): Especifica la fuente de datos.
  • usersByUsernameQuery: Consulta SQL para obtener los detalles del usuario.
  • authoritiesByUsernameQuery: Consulta SQL para obtener los roles del usuario.

Ejercicios Prácticos

Ejercicio 1: Configuración Básica de Seguridad

  1. Añade la dependencia de Spring Security a tu proyecto.
  2. Crea una clase de configuración de seguridad que permita el acceso sin autenticación a la ruta /public/** y requiera autenticación para cualquier otra ruta.

Ejercicio 2: Configuración de Usuarios en Memoria

  1. Configura dos usuarios en memoria: uno con el rol USER y otro con el rol ADMIN.
  2. Configura las rutas /user/** y /admin/** para que solo sean accesibles por usuarios con los roles correspondientes.

Ejercicio 3: Integración con Base de Datos

  1. Configura una base de datos MySQL para almacenar usuarios y roles.
  2. Configura la autenticación en tu aplicación Spring Boot para usar la base de datos.

Soluciones

Ejercicio 1

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Ejercicio 2

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("{noop}password").roles("USER")
            .and()
            .withUser("admin").password("{noop}admin").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Ejercicio 3

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication()
            .dataSource(dataSource)
            .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?")
            .authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
}

Conclusión

En esta sección, hemos aprendido cómo configurar Spring Security en una aplicación Spring Boot. Hemos cubierto la configuración básica, la personalización de la autenticación y la autorización, y la integración con bases de datos. Con estos conocimientos, puedes asegurar tu aplicación Spring Boot y proteger tus rutas y recursos de manera efectiva. En el próximo tema, exploraremos cómo implementar la autenticación JWT en Spring Boot.

Curso de Spring Boot

Módulo 1: Introducción a Spring Boot

Módulo 2: Conceptos Básicos de Spring Boot

Módulo 3: Construyendo Servicios Web RESTful

Módulo 4: Acceso a Datos con Spring Boot

Módulo 5: Seguridad en Spring Boot

Módulo 6: Pruebas en Spring Boot

Módulo 7: Funciones Avanzadas de Spring Boot

Módulo 8: Despliegue de Aplicaciones Spring Boot

Módulo 9: Rendimiento y Monitoreo

Módulo 10: Mejores Prácticas y Consejos

© Copyright 2024. Todos los derechos reservados