I want to create custom error message for Forbidden error. I tried this:
Spring Security Configuration:
@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("/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().accessDeniedHandler(accessDeniedHandler());
// Apply JWT
http.apply(new JwtTokenFilterConfigurer(jwtTokenProvider));
// Optional, if you want to test the API from a browser
// http.httpBasic();
}
@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();
// }
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
}
Custom handler:
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
public static final Logger LOG = LoggerFactory.getLogger(CustomAccessDeniedHandler.class);
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
String jsonPayload = "{\"messffffffage\" : \"%s\", \"timestamp\" : \"%s\" }";
response.getOutputStream().println(String.format(jsonPayload, exc.getMessage(), Calendar.getInstance().getTime()));
}
}
But I get the default error message:
{
"timestamp": "2020-06-09T21:23:32.528+00:00",
"status": 403,
"error": "Forbidden",
"message": "",
"path": "/engine/users/request"
}
Do you know how I can implement the handler proprly?
Just add AuthenticationEntryPoint
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
and configure it in configuration class
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate").permitAll()
.anyRequest().authenticated()
.and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(requestFilter, UsernamePasswordAuthenticationFilter.class);
}
you can write custom message in JwtAuthenticationEntryPoint
(name is user defined) class which implements AuthenticationEntryPoint
just add your custom message in the response.sendError(...)
method.