I ask this again, because i !do not know! how to solve this, this is the last time i ask this, because i simply want an answer: either just say you dont answer this or tell me the answer. not like last time where i got a link without context and still dont know what to do(after i read it whole multiple times)… and i dont want to be rude, i just want a clear answer and not a “i talk arount the answer” type. i dont know how to solve this and i used every knowlage i have about the docu, google and other platforms to find the answer. i didnt found it. Its okey for me if people here dont want to answer this, but then say it. its my last try on this platform, otherwise i will leave it be and dont use it anymore.
I am updating security configuration in my project. I tried multiple approaches but couldn’t find out the root cause.
When I’m hitting localhost:8080/auth/login with below payload:
{
"username":"siri",
"password":"siri"
}
or both username and password with “iris”,
I got the 403 Forbidden
current implementation:
https://pastebin.com/P1JS11u5
There are my dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>6.2.4</version>
</dependency>
We will use userDetailsService for getting credentials from database but as my implementation is not working so we’re trying with hardCoded values.
If i use the databse and start a request from Postman, the request is processed and a database request is made, i still get the 403.
everything i know to do, i tryed…
package neyt.backend.auth;
import lombok.RequiredArgsConstructor;
import neyt.backend.requestsresponse.AuthenticationRequest;
import neyt.backend.requestsresponse.AuthenticationResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthenticationController {
private final AuthenticationService service;
@PostMapping("/login")
public ResponseEntity<AuthenticationResponse> authenticate(
@RequestBody AuthenticationRequest request
) {
return ResponseEntity.ok(service.authenticate(request));
}
}
package neyt.backend.auth;
import lombok.RequiredArgsConstructor;
import neyt.backend.config.JwtService;
import neyt.backend.requestsresponse.AuthenticationRequest;
import neyt.backend.requestsresponse.AuthenticationResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class AuthenticationService {
private final UserDetailsService repository;
private final JwtService jwtService;
private final AuthenticationManager authenticationManager;
public AuthenticationResponse authenticate(AuthenticationRequest request) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.getUsername(),
request.getPassword()
)
);
var user = repository.loadUserByUsername(request.getUsername());
var jwtToken = jwtService.generateToken(user);
return AuthenticationResponse.builder()
.token(jwtToken)
.build();
}
}
package neyt.backend.auth;
public class Validate {
public static String validateSearch(String search) {
return search.replaceAll("[^a-zA-Z0-9]", "");
}
}
package neyt.backend.config;
import lombok.RequiredArgsConstructor;
import neyt.backend.repos.BenutzerRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {
private final BenutzerRepository repository;
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(username ->repository
.findByBenutzerName(username)
.orElseThrow(
() -> new UsernameNotFoundException("User not found")
)
);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails cyberthekAdmin = User.builder()
.username("iris")
.password(passwordEncoder().encode("iris"))
.roles("ADMIN")
.build();
UserDetails cyberthekUser = User.builder()
.username("siri")
.password(passwordEncoder().encode("siri"))
.roles("USER")
.build();
UserDetails cyberthekLogin = User.builder()
.username("login")
.password(passwordEncoder().encode("xSpeQs55ygGSz8LP02YgV8s5J3GMOfQF"))
.roles("LOGIN")
.build();
return new InMemoryUserDetailsManager(cyberthekAdmin, cyberthekUser, cyberthekLogin);
}
}
package neyt.backend.config;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import neyt.backend.entities.Benutzer;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || authHeader.isBlank()) {
filterChain.doFilter(request, response);
return;
}
String token = authHeader.substring(7);
String username = jwtService.extractUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if(jwtService.isTokenValid(token, userDetails)){
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
filterChain.doFilter(request, response);
}
}
package neyt.backend.config;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import javax.crypto.SecretKey;
@Service
public class JwtService {
private static final String SECRET_KEY = "MYSECRET, Replaced with text for Stackoverflow";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
public String generateToken(UserDetails userDetails) {
return generateToken(new HashMap<>(), userDetails);
}
public String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
return Jwts
.builder()
.claims(extraClaims)
.subject(userDetails.getUsername())
.issuedAt(new Date(System.currentTimeMillis()))
.expiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24))
.signWith(getSignInKey())
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
}
private boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
private Claims extractAllClaims(String token) {
return Jwts.parser()
.verifyWith(getSignInKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
private SecretKey getSignInKey() {
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
return Keys.hmacShaKeyFor(keyBytes);
}
}
package neyt.backend.config;
public enum Role {
USER,
ADMIN
}
package neyt.backend.config;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final ApplicationConfig applicationConfig; // Injizieren Sie die ApplicationConfig
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(req -> req
.requestMatchers("/auth/login")
.permitAll()
.anyRequest()
.authenticated())
.userDetailsService(applicationConfig.userDetailsService()) // Verwenden Sie den InMemoryUserDetailsManager
.authenticationProvider(applicationConfig.authenticationProvider())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
package neyt.backend.config;
//
//import neyt.backend.repos.BenutzerRepository;
//import org.springframework.security.core.userdetails.UserDetails;
//import org.springframework.security.core.userdetails.UserDetailsService;
//import org.springframework.security.core.userdetails.UsernameNotFoundException;
//import org.springframework.stereotype.Service;
//
//@Service
//public class UserDetailsImpl implements UserDetailsService {
//
// private final BenutzerRepository repo;
//
// public UserDetailsImpl(BenutzerRepository repo) {
// this.repo = repo;
// }
//
// @Override
// public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// return repo.findByBenutzerName(username)
// .orElseThrow(() -> new UsernameNotFoundException("User not found"));
// }
//}
package neyt.backend.repos;
import neyt.backend.entities.Benutzer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BenutzerRepository extends JpaRepository<Benutzer, Integer> {
Optional<Benutzer> findByBenutzerName(String username);
@Query(value = "SELECT * FROM benutzer WHERE Benutzer_Name = :username", nativeQuery = true)
Benutzer findByBenutzerName2(String username);
}package neyt.backend.service;
import neyt.backend.entities.Benutzer;
import neyt.backend.repos.BenutzerRepository;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class BenutzerService {
private final BenutzerRepository benutzerRepository;
public BenutzerService(BenutzerRepository benutzerRepository) {
this.benutzerRepository = benutzerRepository;
}
public Benutzer getBenutzerIdByUsername(String username) {
return benutzerRepository.findByBenutzerName2(username);
}
}
2