I have implemented JWT authorization system. It works fine, but I should notify client that their token is expired.
I configured my Spring Security:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthEntryPoint unauthorizedHandler;
@Bean
public JwtAuthTokenFilter authenticationJwtTokenFilter() {
return new JwtAuthTokenFilter();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login", "/signup", "/email-exist", "/username-exist", "/refresh-tokens", "/public/**").permitAll()
.antMatchers("/api/trainer/default-config").hasRole(Role.ROLE_ADMIN.name().replace("ROLE_",""))
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler);
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAt(this.corsFilter(), CorsFilter.class);
}
}
So if I catch TokenExpiredException or SignatureVerificationException in my AuthFilter, I want notify clients with messages: Token is expired or Token is invalid
@Slf4j
public class JwtAuthTokenFilter extends OncePerRequestFilter {
@Autowired
private TokenProvider tokenProvider;
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
JwtAuthEntryPoint authenticationEntryPoint;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
try {
String actionToken = tokenProvider.getToken(request);
if (actionToken !=null) {
String username = tokenProvider.getUserNameFromJwtToken(actionToken);
List<GrantedAuthority> authorities = tokenProvider.getAuthoritiesFromJwtToken(actionToken);
UsernamePasswordAuthenticationToken authentication
= new UsernamePasswordAuthenticationToken(userDetailsService.loadUserByUsername(username), null, authorities);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (IllegalArgumentException e) {
logger.error("an error occured during getting username from token", e);
} catch (TokenExpiredException e) {
logger.warn("the token is expired and not valid anymore", e);
} catch(SignatureVerificationException e){
logger.error("Someone change the token!");
} catch (Exception e) {
log.error("Can NOT set user authentication -> Message: {}", e);
}
filterChain.doFilter(request, response);
}
}
Also I have an exceptionHandler for Authentication
@Component
@Slf4j
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException e)
throws IOException, ServletException {
log.error(e.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
}
}
If token is expired or invalid I always send message Full authentication is required to access this resource. But I must notify my client about expired tokens.
I tried to call commence method inside my JwtAuthTokenFilter but it doesn't work :
} catch (TokenExpiredException e) {
authenticationEntryPoint.commence(request, response, new CredentialsExpiredException(e.getMessage()));
logger.warn("the token is expired and not valid anymore", e);
} catch(SignatureVerificationException e){
authenticationEntryPoint.commence(request, response, new BadCredentialsException(e.getMessage()));
logger.error("Someone change the token!");
}
So is there any way to pass through my exceptions with messages about tokens into JwtAuthEntryPoint?