< /ol>
зависимости < /p>
plugins {
id 'application'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
// Ensures compatibility with Spring Cloud
mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.1"
}
}
dependencies {
// Spring Boot core and web framework
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
// Monitoring & health endpoints
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Early loading of remote configurations
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
// DB connection Driver
implementation 'mysql:mysql-connector-java:8.0.33'
// Relational database access with JPA and Spring Data
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// API security and JWT token validation (OAuth2)
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
// Lombok - Auto-generates boilerplate (getters, setters, constructors)
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
// ModelMapper - For mapping between DTOs and entities
implementation 'org.modelmapper:modelmapper:3.2.0'
// JJWT - Java JWT library for token generation, signing, and validation
implementation 'io.jsonwebtoken:jjwt-api:0.12.5' // JWT API (interfaces)
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' // Default implementation
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' // Jackson-based JSON parser
// Optional utilities like caching, collections (Guava)
implementation 'com.google.guava:guava:33.0.0-jre'
// Testing support
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
application {
mainClass = 'org.AuthService.App'
}
< /code>
Конфигурация безопасности < /p>
package org.AuthService.auth;
import lombok.Data;
import org.AuthService.repositories.UserRepository;
import org.AuthService.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableMethodSecurity
@Data
public class SecurityConfig {
@Autowired
private final PasswordEncoder passwordEncoder;
@Autowired
private final UserDetailsServiceImpl userDetailsServiceImpl;
@Bean
@Autowired
public UserDetailsService userDetailsService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
return new UserDetailsServiceImpl(userRepository, passwordEncoder);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, JwtAuthFilter jwtAuthFilter) throws Exception {
httpSecurity
.csrf(csrf -> csrf
.disable()
)
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.POST, "/auth/v1/login", "/auth/v1/refreshToken", "/auth/v1/signup")
.permitAll()
.anyRequest()
.authenticated()
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(Customizer.withDefaults())
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.authenticationProvider(authenticationProvider());
return httpSecurity.build();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsServiceImpl);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return authenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
< /code>
jwt filter < /p>
package org.AuthService.auth;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import org.AuthService.services.JwtService;
import org.AuthService.services.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
@AllArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
@Autowired
private final JwtService jwtService;
@Autowired
private final UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
String token = null;
String username = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
token = authHeader.substring(7);
username = jwtService.extractUsername(token);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtService.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
< /code>
Disabling CSRF and CORS via .csrf().disable().cors().disable()
Ensuring permitAll() is on the signup route
Testing from Postman with no Authorization or CSRF headers
Cleaning and rebuilding the project: ./gradlew clean bootRun
Confirming endpoint is hit and mapped correctly
< /code>
Why does Spring Security still return 403 CSRF on POST if CSRF is disabled?
Why is the 401 still triggered even though /auth/v1/signup is permitted?
Any workaround (restructure/filter ordering/config?) that gets this JWT-authenticated API working properly for public endpoints like signup/login?
Подробнее здесь: https://stackoverflow.com/questions/796 ... -on-public