Tom van den Bogaart
Tom van den Bogaart

Reputation: 143

JWT token in Spring Boot configuration problem

I'm having the problem that when I call the post request: localhost:8080/authenticate The security of my applications says it need and token. When the request is called, filters go over it, so this is not the intention. Now the security asks for a bearer token while this is the first request and that of course it is not present yet. I'm getting the error JWT Token does not begin with Bearer String

My configure method:

@Override
    protected void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/authenticate");
    }

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .cors().disable()
                .authorizeRequests()
                .antMatchers("/authenticate").permitAll()
                .antMatchers("/**/private/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
    }

My filter method:

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {

        final String requestTokenHeader = request.getHeader("Authorization");
        System.out.println("JWT Request: " + request.getRequestURI());
        System.out.println("JWT Contain: " + request.getRequestURI().contains("authenticate"));
        String username = null;
        String jwtToken = null;
        //Remove comment for second approach
        if (request.getRequestURI().contains("authenticate") == false) {
            System.out.println("Do Noting, Permit It");
            chain.doFilter(request, response);
        } else if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtil.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");
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

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

            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }

My controller class:

@RestController
@CrossOrigin
public class JwtAuthenticationController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private JwtUserDetailsService userDetailsService;

    @RequestMapping(value = "/authenticate", method = RequestMethod.POST)
    public ResponseEntity<?> createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception {

        authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword());

        final UserDetails userDetails = userDetailsService
                .loadUserByUsername(authenticationRequest.getUsername());

        final String token = jwtTokenUtil.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(userDetailsService.save(user));
    }

    private void authenticate(String username, String password) throws Exception {
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (DisabledException e) {
            throw new Exception("USER_DISABLED", e);
        } catch (BadCredentialsException e) {
            throw new Exception("INVALID_CREDENTIALS", e);
        }
    }
}

I want the program work so that when I send the localhost:8080/authenticate request there will be no filters, but when I call every other request there will be the filters to check if the token is present.

Thank You in advance.

Upvotes: 1

Views: 9326

Answers (1)

shazin
shazin

Reputation: 21903

Override the method configure(WebSecurity web) to ignore /authenticate endpoint so that it will not be included in Spring Security Filter Chain as below;

public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/authenticate");                
}

Upvotes: 2

Related Questions