why spring returns 401 html page instead of my custom json api response with error? and what is the best way to fix it (override spring config)
security:
@Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { http .httpBasic().disable() .csrf().disable() .cors().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/v2/api-docs").permitAll() .antMatchers("/configuration/ui").permitAll() .antMatchers("/swagger-resources/**").permitAll() .antMatchers("/configuration/security").permitAll() .antMatchers("/swagger-ui.html").permitAll() .antMatchers("/swagger-ui/*").permitAll() .antMatchers("/webjars/**").permitAll() .antMatchers("/v2/**").permitAll() .antMatchers(LOGIN_ENDPOINT, REGISTER_ENDPOINT, "/v2/api-docs", "/swagger-ui.html", "/v2/swagger-ui.html").permitAll() .antMatchers(ADMIN_ENDPOINT).hasRole("ADMIN") .anyRequest().authenticated() .and() .apply(new JwtConfigurer(jwtTokenProvider)); }
Filter:
public class JwtTokenFilter extends GenericFilterBean { private final JwtTokenProvider jwtTokenProvider; public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) { this.jwtTokenProvider = jwtTokenProvider; } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { String token = jwtTokenProvider.resolveToken((HttpServletRequest) req); try { if (token != null && jwtTokenProvider.isTokenValid(token)) { var authentication = jwtTokenProvider.getAuthentication(token); if (authentication != null) { SecurityContextHolder.getContext().setAuthentication(authentication); } } } catch (JwtAuthenticationException e) { SecurityContextHolder.clearContext(); ((HttpServletResponse) res).sendError(e.getHttpStatus().value()); ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED); filterChain.doFilter(req, res); throw new JwtAuthenticationException("JWT token is expired or invalid", HttpStatus.UNAUTHORIZED); } filterChain.doFilter(req, res); } }
so i implemented custom exception handler and filter, and what i need is this type of error
{ "errorMessage": "Invalid username or password", "validationErrors": null }
that what i get when login fo example, success case to get token is also working
{ "username": "vovaflex", "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ2b3ZhZmxleCIsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJpYXQiOjE2MTk4NjQ2MDksImV4cCI6MTYxOTg2ODIwOX0.Oc7AG5ZncfAT3QB8l0mkYDkBr5ZjBfJ2MxLe3M12DF8", "roles": [ { "id": 1, "created": "2021-04-03T18:14:51.891+00:00", "updated": "2021-04-03T18:14:51.891+00:00", "status": "ACTIVE", "name": "ROLE_USER", "users": null } ] }
but whey for example token is not correct or expired or so, i get 401 unauthorized (correct) but instead of json with message that i set up i get full html page with error
<!doctype html> <html lang="en"> <head> <title>HTTP Status 401 – Unauthorized</title> </head> <body> <h1>HTTP Status 401 – Unauthorized</h1> </body> </html>
Advertisement
Answer
For custom JSON error block, you need to do two things
Implement the AuthenticationEntryPoint
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException, ServletException {
}
}
and add that reference in the websecurity settings configure(HttpSecurity http)
@Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint()) ; } }
check these two resources for more details