I have an application that was working with JWT auth (without Redis)Actually I'm implementing Redis but I'm having some errors that I don't understand..
We I sign in, the jwt token is responded ( but not created in redis.. why ? )And another problem is that when i make a request, it throws...common.security.specific.jwt.JwtUtil.extractToken(javax.servlet.http.HttpServletRequest)" because "this.jwtUtil" is null
I added all the code in order to find any relevant information that can be responsible of these bug..Thanks for any help !
JwtUtil.java
@Servicepublic class JwtUtil { /** * Get the token from authorization header. * * @param request * @return token */ public String extractToken(HttpServletRequest request) { String authHeader = request.getHeader(JwtConstant.AUTHORIZATION_HEADER_STRING); if (authHeader.startsWith(JwtConstant.TOKEN_BEARER_PREFIX)) { return authHeader.replace(JwtConstant.TOKEN_BEARER_PREFIX, ""); } return null; }}...
JwtTokenFilter.java
@Servicepublic class JwtTokenFilter extends OncePerRequestFilter { private UserDetailsService userDetailsService; private TokenService tokenService; private JwtTokenProvider jwtTokenProvider; private JwtUtil jwtUtil; public JwtTokenFilter(UserDetailsService userDetailsService, TokenService tokenService, JwtTokenProvider jwtTokenProvider, JwtUtil jwtUtil) { this.userDetailsService = userDetailsService; this.tokenService = tokenService; this.jwtTokenProvider = jwtTokenProvider; this.jwtUtil = jwtUtil; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { try { // Check for authorization header existence. String header = request.getHeader(JwtConstant.AUTHORIZATION_HEADER_STRING); if (header == null || !header.startsWith(JwtConstant.TOKEN_BEARER_PREFIX)) { chain.doFilter(request, response); return; } // Validate request.. UsernamePasswordAuthenticationToken authorization = authorizeRequest(request); SecurityContextHolder.getContext().setAuthentication(authorization); chain.doFilter(request, response); } catch (Exception e) { SecurityContextHolder.clearContext(); throw new InternalServerErrorException(e.toString()); } } private UsernamePasswordAuthenticationToken authorizeRequest(HttpServletRequest request) { try { // Get token. String token = this.jwtUtil.extractToken(request); // ***PROBLEM IS HERE*** if (token != null) { // Get token key. JwtModel model = (JwtModel) this.tokenService.getSecretKey(token); // Validate token. Claims claims = this.jwtTokenProvider.validateToken(model); // Validate user authority/role if allowed to do the api dto. String user = claims.getSubject(); System.out.println("user" + user); UserDetails userDetails = this.userDetailsService.loadUserByUsername(user); if (userDetails != null) { return new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities()); } } } catch (Exception e) { throw new RuntimeException(e); } return null; }}
JwtTokenFilterConfigurer.java
public class JwtTokenFilterConfigurer extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authManager; private TokenService tokenService; private JwtTokenProvider jwtTokenProvider; @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { try { // Map dto value. UserDataDTO req = this.getCredentials(request); // Authenticate user. return this.authManager.authenticate(new UsernamePasswordAuthenticationToken( req.getEmail(), req.getPassword())); } catch (Exception e) { throw new RuntimeException(e); } } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) { try { SecurityContextHolder.getContext().setAuthentication(auth); // Create token. System.out.println("Je passe"); JwtModel model = this.jwtTokenProvider.createToken(((User) auth.getPrincipal()).getUsername()); // Set token. this.tokenService.setSecretKey(model.getToken(), model); // Set key expiration on redis. this.tokenService.setKeyExpiration(model.getToken(), model.getExpDate()); // Add token to authorization header. response.addHeader(JwtConstant.AUTHORIZATION_HEADER_STRING, JwtConstant.TOKEN_BEARER_PREFIX + model.getToken()); } catch (Exception e) { throw new RuntimeException(e); } } private UserDataDTO getCredentials(HttpServletRequest request) { // Map dto value. UserDataDTO auth = null; try { auth = new ObjectMapper().readValue(request.getInputStream(), UserDataDTO.class); } catch (IOException e) { e.printStackTrace(); } return auth; }}
JwtTokenProvider.java
@Componentpublic class JwtTokenProvider { @Value("${security.jwt.token.secret-key") private String secretKey; @Value("${security.jwt.token.expire-length}") private long validityInMilliseconds; // 1h @Value("${security.jwt.token.issuer}") private String issuer; // 1h @Autowired private MyUserDetails myUserDetails; @Autowired private UserJpaRepository userJpaRepository; @PostConstruct protected void init() { secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); } public JwtModel createToken(String email) { AppUser user = userJpaRepository.findByEmail(email); Claims claims = Jwts.claims().setSubject(email); claims.put("auth", user.getAppUserRoles().stream().map(s -> new SimpleGrantedAuthority(s.getAuthority())) .filter(Objects::nonNull).collect(Collectors.toList())); Date current = new Date(); Date expiration = generateTokenExp(JwtConstant.ACCESS_TOKEN_EXPIRATION); String token = Jwts.builder() .setIssuer(issuer) .setClaims(claims) .setIssuedAt(current) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS512, secretKey) .compact(); return new JwtModel(token, issuer, email, current, expiration); } public Authentication getAuthentication(String token) { UserDetails userDetails = myUserDetails.loadUserByUsername(getEmail(token)); return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities()); } public String getEmail(String token) { return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); } public String resolveToken(HttpServletRequest req) { String bearerToken = req.getHeader("Authorization"); if (bearerToken != null && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } public Claims validateToken(JwtModel model) { try { Claims claims = Jwts.parser() .requireIssuer(model.getIssuer()) .requireSubject(model.getSubject()) .requireIssuedAt(model.getIssueDate()) .requireExpiration(model.getExpDate()) .setSigningKey( secretKey) .parseClaimsJws(model.getToken()) .getBody(); return claims; } catch (JwtException | IllegalArgumentException e) { throw new InternalServerErrorException("Expired or invalid JWT token"); } } private Date generateTokenExp(Integer timeExpired) { Date current = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(current); calendar.add(Calendar.MINUTE, timeExpired); return calendar.getTime(); }}
WebSecurityConfig.java
@Configuration@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true)public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService; private JwtTokenProvider jwtTokenProvider; private JwtUtil jwtUtil; private TokenService tokenService; @Override protected void configure(HttpSecurity http) throws Exception { // Disable CSRF (cross site request forgery) http.csrf().disable(); // No session will be created or used by spring security http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // Entry points http.authorizeRequests()// .antMatchers("/users/signin").permitAll()// .antMatchers("/users/signup").permitAll()// .antMatchers("/h2-console/**/**").permitAll() // Disallow everything else.. .anyRequest().authenticated(); // If a user try to access a resource without having enough permissions http.exceptionHandling().accessDeniedPage("/login"); // Apply JWT http.addFilterBefore(new JwtTokenFilter( userDetailsService, tokenService, jwtTokenProvider, jwtUtil), UsernamePasswordAuthenticationFilter.class); } @Override public void configure(WebSecurity web) throws Exception { // Allow swagger to be accessed without authentication web.ignoring().antMatchers("/v2/api-docs")// .antMatchers("/swagger-resources/**")// .antMatchers("/swagger-ui.html")// .antMatchers("/configuration/**")// .antMatchers("/webjars/**")// .antMatchers("/public") // Un-secure H2 Database (for testing purposes, H2 console shouldn't be // unprotected in production) .and() .ignoring() .antMatchers("/h2-console/**/**") ; ; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(12); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }}