'spring security authorization error 401 unauthorized

I'm new to spring security and I am trying to create a web application with Jwt Token the problem is that i cant authenticate it always give me 401 error with i try to login with Postman using data that i stored in database {"username":"login","password":"login"} this is my code that i copy from this website :https://www.techgeeknext.com/spring/spring-boot-security-token-authentication-jwt-mysql

JwtAuthenticationEntryPoint

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

private static final long serialVersionUID = -7858869558953243875L;

@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException authException) throws IOException, ServletException {
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}

JwtRequestFilter

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private JwtUserDetailsService jwtUserDetailsService;
@Autowired
private JwtUtil jwtUtil;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    final String requestTokenHeader = request.getHeader("Authorization");
    String username = null;
    String jwtToken = null;
    // JWT Token is in the form "Bearer token". Remove Bearer word and get only the
    // Token
    if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
        jwtToken = requestTokenHeader.substring(7);
        try {
            username = jwtUtil.getUsernameFromToken(jwtToken);
        } catch (IllegalArgumentException e) {
            System.out.println("Unable to get JWT Token");
        } catch (ExpiredJwtException e) {
            System.out.println("JWT Token has expired");
        }
    } else {
        logger.warn("JWT Token does not begin with Bearer String");
    }

    // Once we get the token validate it.
    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

        UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);

        // if token is valid configure Spring Security to manually set authentication
        if (jwtUtil.validateToken(jwtToken, userDetails)) {

            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            usernamePasswordAuthenticationToken
                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            // After setting the Authentication in the context, we specify
            // that the current user is authenticated. So it passes the Spring Security
            // Configurations successfully.
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
    }
    filterChain.doFilter(request, response);
}

JwtUtil

@Component
public class JwtUtil implements Serializable {

private static final long serialVersionUID = -2550185165626007488L;
public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;

@Value("${jwt.secret}")
private String secret;

public void setSecret(String secret) {
    this.secret = secret;
}

public String getUsernameFromToken(String token) {
    return getClaimFromToken(token, Claims::getSubject);
}

public Date getIssuedAtDateFromToken(String token) {
    return getClaimFromToken(token, Claims::getIssuedAt);
}

public Date getExpirationDateFromToken(String token) {
    return getClaimFromToken(token, Claims::getExpiration);
}

public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
    final Claims claims = getAllClaimsFromToken(token);
    return claimsResolver.apply(claims);
}

private Claims getAllClaimsFromToken(String token) {
    return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}

private Boolean isTokenExpired(String token) {
    final Date expiration = getExpirationDateFromToken(token);
    return expiration.before(new Date());
}

private Boolean ignoreTokenExpiration(String token) {
    // here you specify tokens, for that the expiration is ignored
    return false;
}

public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return doGenerateToken(claims, userDetails.getUsername());
}

private String doGenerateToken(Map<String, Object> claims, String subject) {

    return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
            .signWith(SignatureAlgorithm.HS512, secret).compact();
}

public Boolean canTokenBeRefreshed(String token) {
    return (!isTokenExpired(token) || ignoreTokenExpiration(token));
}

public Boolean validateToken(String token, UserDetails userDetails) {
    final String username = getUsernameFromToken(token);
    return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}

WebSecurityConfig

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService userDetailsService;

@Autowired
private JwtRequestFilter jwtRequestFilter;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    // configure AuthenticationManager so that it knows from where to load
    // user for matching credentials
    // Use BCryptPasswordEncoder
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}



@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();

}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception{
 // We don't need CSRF for this example
        httpSecurity.csrf().disable().cors().disable()
        .exceptionHandling()
        .authenticationEntryPoint(jwtAuthenticationEntryPoint)
        .and()
        .formLogin().disable()
        .sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and().authorizeRequests()
        .antMatchers("/authenticate", "/register/**").permitAll();
                    httpSecurity.addFilterBefore(jwtRequestFilter, 
    UsernamePasswordAuthenticationFilter.class);

    }

This is my User Entity

@Entity(name = "UserTable")

public class UserTable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id_utilisateur;

private String username;
private String password;

public UserTable() {
    super();
}
public UserTable(long id_utilisateur, String username, String password) {
    super();
    this.id_utilisateur = id_utilisateur;

    this.username = username;
    this.password = password;
    
}
public long getId_utilisateur() {
    return id_utilisateur;
}
public void setId_utilisateur(long id_utilisateur) {
    this.id_utilisateur = id_utilisateur;
}
public String getUsername() {
    return username;
}
public void setUsername(String username) {
    this.username = username;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}

My JwtUserDetailsService

@Service
public class JwtUserDetailsService implements UserDetailsService {

@Autowired
private UtilisateurRepository userRepository;

@Autowired
private PasswordEncoder bcryptEncoder;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    UserTable userTable=userRepository.findByUsername(username);
    if (userTable == null) {
        throw new UsernameNotFoundException("User not found with username: " + username);
    }
    return new org.springframework.security.core.userdetails.User(userTable.getUsername(), 
  userTable.getPassword(),
            new ArrayList<>());
}

public Object save(UserDto user) {
    UserTable newUser=new UserTable();
    newUser.setUsername(user.getUsername());
    newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
    return userRepository.save(newUser);
}

And finnally my controller

@RestController
@CrossOrigin
public class JwtAuthenticationController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private JwtUserDetailsService userDetailService;

@RequestMapping(value = "/reda", method = RequestMethod.POST)
public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) 
   throws Exception {
    try {
    authenticationManager.authenticate(new 
    UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(),
            authenticationRequest.getPassword()));
    } catch (DisabledException e) {
        throw new Exception("USER_DISABLED", e);
    } catch (BadCredentialsException e) {
        throw new Exception("INVALID_CREDENTIALS", e);
    }
    final UserDetails userDetails = 
   userDetailService.loadUserByUsername(authenticationRequest.getUsername());

    final String token = jwtUtil.generateToken(userDetails);

    return ResponseEntity.ok(new JwtResponse(token));

}

@RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<?> saveUser(@RequestBody UserDto user) throws Exception {
    return ResponseEntity.ok(userDetailService.save(user));
}


Solution 1:[1]

Please provide the "Credentials" within the UsernamePasswordAuthenticationToken (userDetails.getPassword() in your example).

UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                    userDetails, userDetails.getPassword(), userDetails.getAuthorities());

Your WebSecurityConfig compare the password with the "BCryptPasswordEncoder" and if you provide a "null" password, the result will fail.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Paul Franke