Token is generating as null for login using springboot

Viewed 57

I would like to generate the token for login using springboot, The token is generating while checking using postman, but I am getting null in console

Authenticate controller

package com.demo.grocery.controller;

import com.demo.grocery.config.JwtUtils;
import com.demo.grocery.model.JwtRequest;
import com.demo.grocery.model.JwtResponse;
import com.demo.grocery.model.User;
import com.demo.grocery.service.impl.UserDetailsServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;

@RestController
public class AuthenticateController {
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsServiceImpl userDetailsServiceImpl;

    @Autowired
    private JwtUtils jwtUtils;

    //generate token
    @CrossOrigin("http://localhost:4200")
    @PostMapping("/generate-token")
    public ResponseEntity<?> generateToken(@RequestBody JwtRequest jwtRequest) throws Exception
    {

        try {

            this.authenticate(jwtRequest.getUsername(), jwtRequest.getPassword());

        } catch (UsernameNotFoundException e) {
            // TODO: handle exception
            e.printStackTrace();
            throw new Exception("User Not Found");
        }

        ////////////authenticate
        UserDetails userDetails =  this.userDetailsServiceImpl.loadUserByUsername(jwtRequest.getUsername());

        String token = this.jwtUtils.generateToken(userDetails);

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

    }

    private void authenticate(String username, String password) throws Exception
    {
        try {

            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));

        } catch (DisabledException e) {

            e.printStackTrace();
            throw new Exception("USER DISABLED "+e.getMessage());
        }

        catch(BadCredentialsException e)
        {
            throw new Exception("Invalid Credentials "+e.getMessage());
        }
    }

    //returns the details of current logged in user
    @CrossOrigin("http://localhost:4200")
    @GetMapping("/current-user")
    public User getCurrentUser(Principal principal)
    {
        return (User) this.userDetailsServiceImpl.loadUserByUsername(principal.getName());


    }
}

JwtAuthenticationFilter

package com.demo.grocery.config;

import com.demo.grocery.service.impl.UserDetailsServiceImpl;

import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
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.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtUtils jwtUtil;

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

        final String requestTokenHeader = request.getHeader("Authorization");

        System.out.println(requestTokenHeader);

        String username = null;
        String jwtToken = null;

        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            // yes

            jwtToken = requestTokenHeader.substring(7);
            try {

                username = this.jwtUtil.extractUsername(jwtToken);

            } catch (ExpiredJwtException e) {

                e.printStackTrace();
                System.out.println("jwt token has expired..");
            }

            catch (Exception e) {

                e.printStackTrace();
                System.out.println("error");
            }

        }

        else {
            System.out.println("Invalid Token, Not Starts with bearer String");
        }

        //validate Token
        if(username!=null && SecurityContextHolder.getContext().getAuthentication() == null)
        {
            final UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

            if(this.jwtUtil.validateToken(jwtToken, userDetails))
            {
                //token is valid
                UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                usernamePasswordAuthentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthentication);

            }
            else
            {
                System.out.println("Token is not Valid");
            }
        }

        filterChain.doFilter(request, response);
    }

}

Service

package com.demo.grocery.service.impl;

import com.demo.grocery.model.User;
import com.demo.grocery.repository.UserRepo;

import org.springframework.beans.factory.annotation.Autowired;
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 UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserRepo userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = this.userRepository.findByUsername(username);

        if (user == null) {
            System.out.println("User Not Found");
            throw new UsernameNotFoundException("No User Found!!");
        }
        return user;
    }

}

Output in intelliji

Output

Postman output Generating Token

Getting current user details

Look into the screenshots and help me to solve the issue. Why it is storing as null?

1 Answers

For your method to work you should pass your JWT in Postman using Authorization -> Type: Bearer Token.

Postman example

As you can see in your console log, there's a message "Invalid Token, Not Starts with bearer String", which is printed from your JwtAuthenticationFilter when there's no Authorization header or it doesn't start with "Bearer".
At this point your user is not authenticated, so there's no Principal object in SecurityContextHolder when controller method is executed.

For these cases you should convert response to 401 UNAUTHORIZED status. For example, you can do it in your filter by writing straight to response.

But implementing your own security mechanism is considered a bad practice. I advise to use spring-security build-in JWT-support, which will automatically respond with 401 when there's no valid token found in Authorization header and will store additional info about missing or invalid token at response WWW-Authenticate header.
Take a look at spring-security official sample of jwt-secured resource-server.

Related