I am creating an application and want to use jwt as authentication mechanism. I have implemented the security configurations for jwt but its giving 403 for all my request.
In securityFilterChain method I have added the endpoints where I dont want authentication to be done.
I am using mysql as database and have added the info in application.properties
package com.abhinav.mangadownloader.common;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
public SecurityConfiguration(
JwtAuthenticationFilter jwtAuthenticationFilter
) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
System.out.println("Http : "+ http.toString());
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/user-add").permitAll()
.anyRequest().authenticated()).csrf(AbstractHttpConfigurer::disable);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
http.sessionManagement(sessionCreationPolicy -> sessionCreationPolicy.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
System.out.println("authenticationManager");
return authConfig.getAuthenticationManager();
}
}
package com.abhinav.mangadownloader.common;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
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.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private JwtTokenProvider jwtTokenProvider;
private CustomeruserDetailsService userDetailsService;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider, CustomeruserDetailsService userDetailsService) {
this.jwtTokenProvider = jwtTokenProvider;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
System.out.println("doFilterInternal");
System.out.println("URI: " + request.getRequestURI());
String token = getTokenFromRequest(request);
if(StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {
String username = jwtTokenProvider.getUsername(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
System.out.println("doFilterInternal End");
filterChain.doFilter(request, response);
}
private String getTokenFromRequest(HttpServletRequest request){
System.out.println("getTokenFromRequest");
try {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
package com.abhinav.mangadownloader.common;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
@Component
public class JwtTokenProvider {
private static final Logger logger = LoggerFactory.getLogger(JwtTokenProvider.class);
private final String jwtSecret = "mangadownload";
private final long jwtExpirationDate = 604800000;
public String generateToken(Authentication authentication) {
String username = authentication.getName();
Date expirationDate = new Date(new Date().getTime() + jwtExpirationDate);
return Jwts.builder().setSubject(username).setIssuedAt(new Date())
.setExpiration(expirationDate).signWith(key()).compact();
}
private Key key(){
return Keys.hmacShaKeyFor(
Decoders.BASE64.decode(jwtSecret)
);
}
public String getUsername(String token){
Claims claims = Jwts.parserBuilder()
.setSigningKey(key())
.build()
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
public boolean validateToken(String token){
try{
Jwts.parserBuilder()
.setSigningKey(key())
.build()
.parse(token);
return true;
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}
package com.abhinav.mangadownloader.common;
import com.abhinav.mangadownloader.entity.User;
import com.abhinav.mangadownloader.repository.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@AllArgsConstructor
public class CustomeruserDetailsService implements UserDetailsService {
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername");
User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User Does Not Exist by Username"));
return (UserDetails) user;
}
}
package com.abhinav.mangadownloader.controller;
import com.abhinav.mangadownloader.request.LoginRequest;
import com.abhinav.mangadownloader.request.UserAddRequest;
import com.abhinav.mangadownloader.response.LoginResponse;
import com.abhinav.mangadownloader.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginController {
private final LoginService loginService;
@Autowired
public LoginController(LoginService loginService) {
this.loginService = loginService;
}
@PostMapping("/login")
public LoginResponse login(@RequestBody LoginRequest request) {
return loginService.login(request);
}
@PostMapping("/user-add")
public void addUser(@RequestBody UserAddRequest request){
loginService.userAdd(request);
}
}
I have used custom UserDetailsService not using roles added roles changed functions operations.
I got the answer to my question my mistake was I was not having role in user table entity so when converting in file: CustomeruserDetailsService. It was throwing an error as it was not being converted properly so just added a dummy role and returned the answer as it is.
import com.abhinav.mangadownloader.entity.User;
import com.abhinav.mangadownloader.repository.UserRepository;
import lombok.AllArgsConstructor;
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
@AllArgsConstructor
public class CustomeruserDetailsService implements UserDetailsService {
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("loadUserByUsername");
User user = userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("User Does Not Exist by Username"));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.authorities("USER")
.build();
}
}