SecurityConfig.java
package com.edtech.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
/** Documentação para SecurityConfig. */
@Configuration
@ConditionalOnWebApplication
public class SecurityConfig {
@Value("${cors.allowed-origins:http://localhost:5173}")
private String allowedOrigins;
private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final JwtAuthenticationEntryPoint authenticationEntryPoint;
public SecurityConfig(
JwtAuthenticationFilter jwtAuthenticationFilter,
JwtAuthenticationEntryPoint authenticationEntryPoint) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
this.authenticationEntryPoint = authenticationEntryPoint;
}
/** Documentação. */
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
// API stateless: JWT em header Authorization, imune a CSRF.
.csrf(csrf -> csrf.ignoringRequestMatchers("/**"))
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.sessionManagement(
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.exceptionHandling(
exception -> exception.authenticationEntryPoint(authenticationEntryPoint))
.headers(
headers ->
headers
.httpStrictTransportSecurity(
hsts -> hsts.includeSubDomains(true).maxAgeInSeconds(31536000))
.frameOptions(frame -> frame.deny())
.contentSecurityPolicy(
csp -> csp.policyDirectives("default-src 'self'; frame-ancestors 'none';")))
.authorizeHttpRequests(
auth ->
auth.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.requestMatchers(HttpMethod.POST, "/api/auth/login")
.permitAll()
.requestMatchers(HttpMethod.POST, "/api/auth/login/verify-2fa")
.permitAll()
.requestMatchers(HttpMethod.POST, "/api/auth/register")
.permitAll()
.requestMatchers(HttpMethod.POST, "/api/auth/register/verify")
.permitAll()
.requestMatchers("/api/auth/recovery/**")
.permitAll()
.requestMatchers("/ws-edtech/**")
.permitAll()
.requestMatchers("/actuator/**")
.permitAll()
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html")
.permitAll()
.requestMatchers("/api/**")
.authenticated()
.anyRequest()
.denyAll())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
/** Documentação. */
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(allowedOrigins.split(",")));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Content-Type", "Authorization", "X-XSRF-TOKEN"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}