Hola usuario de nuestro sitio, descubrimos la respuesta a lo que estabas buscando, has scroll y la verás más abajo.
Solución:
Como se señaló en comentarios anteriores, el marco de seguridad rechaza la solicitud antes de que llegue a la capa MVC, por lo que @ControllerAdvice
no es una opción aquí.
Hay 3 interfaces en el marco Spring Security que pueden ser de interés aquí:
- org.springframework.security.web.authentication.AuthenticationSuccessHandler
- org.springframework.security.web.authentication.AuthenticationFailureHandler
- org.springframework.security.web.access.AccessDeniedHandler
Puede crear implementaciones de cada una de estas interfaces para personalizar la respuesta enviada para varios eventos: inicio de sesión exitoso, inicio de sesión fallido, intento de acceder a recursos protegidos con permisos insuficientes.
Lo siguiente devolvería una respuesta JSON en un intento de inicio de sesión fallido:
@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException ex) throws IOException, ServletException
response.setStatus(HttpStatus.FORBIDDEN.value());
Map data = new HashMap<>();
data.put("timestamp", new Date());
data.put("status",HttpStatus.FORBIDDEN.value());
data.put("message", "Access Denied");
data.put("path", request.getRequestURL().toString());
OutputStream out = response.getOutputStream();
com.fasterxml.jackson.databind.ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(out, data);
out.flush();
También debe registrar su(s) implementación(es) con el marco de seguridad. En la configuración de Java, esto se parece a lo siguiente:
@Configuration
@EnableWebSecurity
@ComponentScan("...")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
public void configure(HttpSecurity http) throws Exception
http
.addFilterBefore(corsFilter(), ChannelProcessingFilter.class)
.logout()
.deleteCookies("JESSIONID")
.logoutUrl("/api/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/api/login")
.failureHandler(authenticationFailureHandler())
.successHandler(authenticationSuccessHandler())
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint())
.accessDeniedHandler(accessDeniedHandler());
/**
* @return Custom @link AuthenticationFailureHandler to send suitable response to REST clients in the event of a
* failed authentication attempt.
*/
@Bean
public AuthenticationFailureHandler authenticationFailureHandler()
return new RestAuthenticationFailureHandler();
/**
* @return Custom @link AuthenticationSuccessHandler to send suitable response to REST clients in the event of a
* successful authentication attempt.
*/
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler()
return new RestAuthenticationSuccessHandler();
/**
* @return Custom @link AccessDeniedHandler to send suitable response to REST clients in the event of an attempt to
* access resources to which the user has insufficient privileges.
*/
@Bean
public AccessDeniedHandler accessDeniedHandler()
return new RestAccessDeniedHandler();
En caso de que estés usando @EnableResourceServer
también puede encontrar conveniente extender ResourceServerConfigurerAdapter
en lugar de WebSecurityConfigurerAdapter
en tus @Configuration
clase. Al hacer esto, simplemente puede registrar una cuenta personalizada AuthenticationEntryPoint
anulando configure(ResourceServerSecurityConfigurer resources)
y usando resources.authenticationEntryPoint(customAuthEntryPoint())
dentro del método.
Algo como esto:
@Configuration
@EnableResourceServer
public class CommonSecurityConfig extends ResourceServerConfigurerAdapter
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
resources.authenticationEntryPoint(customAuthEntryPoint());
@Bean
public AuthenticationEntryPoint customAuthEntryPoint()
return new AuthFailureHandler();
También hay un bonito OAuth2AuthenticationEntryPoint
que se puede ampliar (ya que no es definitivo) y reutilizar parcialmente al implementar un personalizado AuthenticationEntryPoint
. En particular, agrega encabezados “WWW-Authenticate” con detalles relacionados con el error.
No puede utilizar las anotaciones del controlador de excepciones Spring MVC como @ControllerAdvice
porque los filtros de seguridad de Spring se activan mucho antes que Spring MVC.
Más adelante puedes encontrar las interpretaciones de otros gestores de proyectos, tú asimismo tienes la habilidad dejar el tuyo si te gusta.