I'm struggling to implement the jwt authentication while i understand (i think so) the theory behind it.
The whole idea is to send a jwt token every time user wants to access personal data through backend secured endpoints, instead of sending the credentials every time.
My backend is based on this repo. I have edited the code for my needs:
JwtTokenFilter.java
public class JwtTokenFilter extends OncePerRequestFilter {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
FilterChain filterChain) throws ServletException, IOException {
// Save initial path. Since CustomErrorController always uses /error path
// we can't retrieve the initial path using httpRequest.getRequestURI() method
httpServletRequest.setAttribute("initialPath", httpServletRequest.getRequestURI());
if (httpServletRequest.getHeader("Authorization") == null) {
throw new TokenException("Authorization field is empty.");
}
String token = jwtTokenProvider.resolveToken(httpServletRequest);
if (token == null) {
throw new TokenException("Non Bearer Token");
}
// throws TokenException
jwtTokenProvider.validateToken(token);
// throws NoUserFoundException
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@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("/signin").permitAll()
// .antMatchers("/signup").permitAll()
// Disallow everything else..
// .antMatchers("/profile").authenticated();
// If a user tries to access a resource without having enough permissions
// http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> {
// System.out.println("**************** INSIDE HANDLEEEEEEEEER");
// response.sendError(417);
// });
// IMPORTANT!!!
// DO I NEED THESE???
// http.authorizeRequests().antMatchers("/signin", "signup").permitAll();
// http.authorizeRequests().antMatchers("/signin", "signup").hasAnyRole("ADMIN", "USER");
// http.authorizeRequests().antMatchers("/signin", "signup").hasAnyRole("ADMIN");
// http.authorizeRequests().antMatchers("/profile").authenticated();
http.antMatcher("/profile").apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Here are my questions: See the commented out code on the WebSecurityConfigurerAdapter. First of, it doesn't seem to work. But even if it did, it wouldn't make sense.
We want the jwt filter to be applied only to specific urls. It wouldn't make sense to ask for a token when everyone has the right to sign up or sign in. The last line inside WebSecurityConfigurerAdapter applies the filter only on the /profile endpoint.
The jwt token contains (if it is valid) the username. When extracted, we search for that user on the database. This user object contains its' role. So, in order to have a user's role we MUST pass through the jwt filter in order to validate it and THEN find the saved user.
So why the code doesn't work at all? Is the commented code really useless or am i missing something? How would it be possible to authenticate the user before even applying the jwt filter?