package es.tatvil.taiageweb.config;
import es.tatvil.taiageweb.servicio.UsuarioService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
/**
* Configuración de seguridad de la aplicación.
*
*
Define las reglas de acceso HTTP, el proveedor de autenticación basado en
* base de datos y la configuración del formulario de login/logout.
*
*
* - Rutas públicas: {@code /}, {@code /login}, {@code /registro}, {@code /leyes},
* {@code /noticias}, {@code /webhook/stripe} y recursos estáticos.
* - Panel admin ({@code /admin/**}): requiere {@code ROLE_ADMIN}.
* - Contenido de pago ({@code /curso/**}, {@code /api/**}): requiere
* {@code ROLE_PAGADO} o {@code ROLE_ADMIN}.
*
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig {
/**
* Crea el {@link PasswordEncoder} BCrypt usado en toda la aplicación.
*
* @return encoder BCrypt con factor de coste por defecto (10)
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* Crea el proveedor de autenticación DAO que consulta {@link UsuarioService}.
*
* @param service servicio que implementa {@link org.springframework.security.core.userdetails.UserDetailsService}
* @param encoder encoder de contraseñas
* @return proveedor configurado
*/
@Bean
public DaoAuthenticationProvider authProvider(UsuarioService service, PasswordEncoder encoder) {
var provider = new DaoAuthenticationProvider(service);
provider.setPasswordEncoder(encoder);
return provider;
}
/**
* Define la cadena de filtros de seguridad HTTP.
*
* @param http objeto de configuración de Spring Security
* @return cadena de filtros construida
* @throws Exception si la configuración es inválida
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.ignoringRequestMatchers("/webhook/stripe"))
.headers(headers -> headers
.frameOptions(frame -> frame.sameOrigin())
)
.authorizeHttpRequests(auth -> auth
// Recursos públicos
.requestMatchers(
"/", "/inicio", "/login", "/registro",
"/leyes", "/noticias", "/acceso-denegado", "/error",
"/webhook/stripe",
"/css/**", "/js/**", "/images/**", "/leyes/**", "/audios/**", "/favicon.ico"
).permitAll()
// Panel de administración
.requestMatchers("/admin/**").hasRole("ADMIN")
// Contenido de pago
.requestMatchers("/curso", "/curso/**", "/planning", "/esquema.html", "/flashcards.html", "/flashcards/**", "/api/**").hasAnyRole("PAGADO", "ADMIN")
// Cualquier otra ruta requiere autenticación
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.usernameParameter("email") // el campo del form se llama "email"
.defaultSuccessUrl("/", false)
.failureUrl("/login?error")
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll()
)
.exceptionHandling(ex -> ex
.accessDeniedPage("/acceso-denegado")
);
return http.build();
}
}