I have implemented some easy method to authenticate users in springboot which returns jwt and validates users but the app stopped giving responses with actual bodies and started sending empty 200 responses any clue why this might be? According to the debugger the program never ends up on the Request I was trying to call but authorization with the jwt is always succesfull
my classes
JWTService
@Service
public class JwtService {
private static final String SECRET_KEY = "32bitkey";
public String extractEmail(String token) {
return exctractClaim(token, Claims::getSubject);
}
public <T> T exctractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
public String generateToken(
UserDetails userDetails) {
return generateToken(Map.of(), userDetails);
}
public String generateToken(
Map<String, Object> extraClaims,
UserDetails userDetails) {
return Jwts
.builder()
.setClaims(extraClaims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
public boolean isTokenValid(String token, UserDetails userDetails) {
final String email = extractEmail(token);
return email.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
public boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
private Date extractExpiration(String token) {
return exctractClaim(token, Claims::getExpiration);
}
private Claims extractAllClaims(String token) {
return Jwts
.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private Key getSigningKey() {
byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
return Keys.hmacShaKeyFor(keyBytes);
}
Security filter chain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity security) throws Exception {
security
.csrf()
.disable()
.authorizeHttpRequests()
.requestMatchers(
"/fixture/getFixturesBySportAndDate",
"/user/register",
"/user/authenticate",
"/league/getLeaguesByFixturePlayedAtDateInSport",
"/team/fillTeamsHockey",
"/fixture/fillFixturesHockey",
"/fixture/fillFixturesBasketball")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthetificationFilter, UsernamePasswordAuthenticationFilter.class);
return security.build();
}
JwtAuthFilter
@Component
@RequiredArgsConstructor
public class JwtAuthetificationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(
@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain
) throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
final String jwt;
final String email;
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
jwt = authorizationHeader.substring(7);
email = jwtService.extractEmail(jwt);
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
if (jwtService.isTokenValid(jwt, userDetails)){
UsernamePasswordAuthenticationToken authenticationToken
= new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
Application Config
@Configuration @RequiredArgsConstructor
public class ApplicationConfig {
private final UserRepository userRepository;
@Bean
public UserDetailsService userDetailsService() {
return username -> userRepository.findByEmail(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
};
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration cfg) throws Exception {
return cfg.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Example request
@GetMapping(value = "/getUserInfo")
public ResponseEntity<User> getUserInfo(HttpServletRequest request){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String email = authentication.getName();
User user = userRepository.findByEmail(email).get();
return ResponseEntity.ok(user);
}
I tried changing basically everything and debugging the info but couldn't get it done because it just gave me the answer that the request never executes
I haven't tried running your code at all, but from first glance it looks like you're not calling up the filter chain after setting the security context's authentication within JwtAuthenticationFilter (although you do if there is no authorization header).
Try adjusting this:
...
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
if (jwtService.isTokenValid(jwt, userDetails)){
UsernamePasswordAuthenticationToken authenticationToken
= new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
to call the next filter in the chain:
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
if (jwtService.isTokenValid(jwt, userDetails)){
UsernamePasswordAuthenticationToken authenticationToken
= new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request)
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
// causes the next filter in the chain to be invoked
filterChain.doFilter(request, response);
Here is the comment in the header of FilterChain for the doFilter
method:
/**
* Causes the next filter in the chain to be invoked, or if the calling
* filter is the last filter in the chain, causes the resource at the end of
* the chain to be invoked.
*
* @param request
* the request to pass along the chain.
* @param response
* the response to pass along the chain.
*
* @throws IOException if an I/O error occurs during the processing of the
* request
* @throws ServletException if the processing fails for any other reason
*/
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException;