I trying to create API with JSON Web Token. Unfortunately once configured, I am having trouble executing queries. Because I get an 401 Unauthorized error - despite successfully generating and sending the token in the heade.
How can I try to figure out what is wrong?
This is my JwtAuthorizationFilter, after send a query with token logger.info(auth.getName()); returns correct username.
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserDetailsService userDetailsService, String secret) {
super(authenticationManager);
this.userDetailsService = userDetailsService;
this.secret = secret;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(request);
if (authenticationToken == null) {
logger.warn("Authentication token is null");
filterChain.doFilter(request, response);
return;
}
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String token = request.getHeader(TOKEN_HEADER);
if (token != null && token.startsWith(TOKEN_PREFIX)) {
logger.info(token);
String userName = JWT.require(Algorithm.HMAC256(secret)).build().verify(token.replace(TOKEN_PREFIX, "")).getSubject();
if (userName != null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(userName);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null,
userDetails.getAuthorities());
logger.info(auth.getName());
return auth;
}
}
return null;
}
This is security config:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.cors().and().csrf(AbstractHttpConfigurer::disable) //
.authorizeHttpRequests(auth -> {
auth.requestMatchers(HttpMethod.GET, "/**").permitAll() //
.requestMatchers(HttpMethod.PUT, "/login").permitAll() //
.requestMatchers(HttpMethod.PUT, "admin/**").authenticated(); //
}).authenticationManager(authenticationManager(authenticationConfiguration)) //
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
.addFilter(authenticationFilter()) //
.addFilter(new JwtAuthorizationFilter(authenticationManager(authenticationConfiguration), userDetailsManager(), secret)) //
.exceptionHandling() //
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)) //
.and().headers().frameOptions().disable().and().build();
}
public JsonObjectAuthenticationFilter authenticationFilter() throws Exception {
JsonObjectAuthenticationFilter authenticationFilter = new JsonObjectAuthenticationFilter(objectMapper);
authenticationFilter.setAuthenticationSuccessHandler(successHandler);
authenticationFilter.setAuthenticationFailureHandler(failureHandler);
authenticationFilter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
return authenticationFilter;
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsManager userDetailsManager() {
return new JdbcUserDetailsManager(dataSource);
}
I tried to change the configuration of securityFilterChain, but change the order of filters, etc. But unfortunately, I can not deal with this problem.
Ok, I found the solution by changing this part:
.authorizeHttpRequests(auth -> {
auth.requestMatchers(HttpMethod.GET, "/**").permitAll() //
.requestMatchers(HttpMethod.PUT, "/login").permitAll() //
.requestMatchers(HttpMethod.PUT, "admin/**").authenticated(); //
})
To this:
.authorizeHttpRequests(auth -> {
auth.requestMatchers(HttpMethod.GET, "/**").permitAll() //
.requestMatchers(HttpMethod.POST, "/login").permitAll() //
.anyRequest().authenticated(); //
}) //
Now it works as I would like, but I still don't understand why it didn't work properly:
requestMatchers(HttpMethod.PUT, "admin/**").authenticated()