I have a org.springframework.web.filter.GenericFilterBean
filter. I would like to throw an exception when user is not authorized and catch this exception with @ControllerAdvice
. But it seems that the handler doesn't do that.
Filter method
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
ClientAuthentication auth = (ClientAuthentication) authenticationService.getAuthentication(httpRequest, httpResponse);
SecurityContextHolder.getContext().setAuthentication(auth);
if (auth.isAuthenticated()) {
chain.doFilter(request, response);
} else {
ObjectMapper mapper = new ObjectMapper();
response.setCharacterEncoding("UTF-8");
httpResponse.getWriter().write(mapper.writeValueAsString(auth.getInfo()));
}
}
It works but a disadvantage is that I want to catch exception and render exception message back to the client with respect to Content-Type
and Accept
HTTP header. This solution renders what I want but into JSON only and my application has to handle XML
and JSON
.
Exception handler
it works when I throw exceptions from @Controller
or @RestController
but not from HTTP filter.
@ControllerAdvice
class GlobalExceptionHandler {
private static final Logger LOGGER = LogManager.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BadRequestException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public
@ResponseBody
ResponseMessage badRequestException(BadRequestException ex) {
return ex.getResponseMessage();
}
/** rest omitted .... **/
}
Update #1
This is my Spring Security config where AuthFilter
filter is set.
@EnableWebSecurity
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Configuration
@Order(1)
public static class ApiSecurity extends WebSecurityConfigurerAdapter {
private static Logger LOG = LogManager.getLogger(ApiSecurity.class);
@Bean
AuthenticationEntryPoint authenticationEntryPoint() {
LOG.debug("authenticationEntryPoint bean");
return new RestAuthenticationEntryPoint();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint())
.and()
.servletApi()
.and()
.headers().cacheControl();
http.antMatcher(ApiController.API_ROOT + "/**").authorizeRequests().anyRequest().authenticated()
.and()
.addFilterBefore(new AuthFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(ApiController.API_ROOT + "/sandbox/**");
}
}
@Configuration
public static class WebFormSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService defaultUserService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(defaultUserService).passwordEncoder(passwordEncoder);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/public/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin()
.loginPage("/login").failureUrl("/login?error").permitAll().and()
.logout().permitAll();
}
}
}