简体   繁体   中英

How to properly redirect login failure on a spring security login for a failed role?

I'm configuring an API and web tandem and I want to set up a separated login for security:

  1. API is accessed without session maintaining and basic authorization , method control access.
  2. Web : for management and backend purposes, authenticated intercepting URL patterns : it lands on a public page and then the other URLs need to be authenticated and with an ADMIN role to be accessed and maybe some with USER role through the login form .

I think that I'm near to achieving it (testing on browser and API testing sofware requests) but the configuration that I post below fails at this:

At web form login if I put an user credential I'm redirected to error but not to the URL that performs logout as it does with an unknown credentials.

    @Configuration
    @Order(1)
    @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
    public static class ApiSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            //super.configure(http);

            http
                 .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                 .csrf().disable()
                 .antMatcher("/api/**")
                 .authorizeRequests()
                    .anyRequest().permitAll()
                    .and()
                 .httpBasic()

//               .authenticationEntryPoint(authenticationEntryPoint());
        }

    } //FIN CONF API

    // MULTIPLES CONFIGURACIONES. SI HACE MATCH POR ORDEN NO SE APLICAN LAS SIGUIENTES.
    @Configuration
    @Order(2) //Sin @Order lo convierte en el ultimo en ser tenido en cuenta.
    public static class WebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {


        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http
                .csrf().disable()
                .authorizeRequests()
                    .antMatchers("/sorteo/**", "/admin/**").hasRole("ADMIN") // ZONA PARA ROL CONCRETO
                    //.antMatchers("/api/**").authenticated()//.hasAnyRole("ADMIN", "USER")//.hasAuthority("TAL1") // CUALQUIERA CON CUENTA
                    .antMatchers("/", "**/favicon.ico", "/resources/static/**").permitAll() //PARTE PUBLICA
                    .anyRequest().permitAll()
                    .and()
                .formLogin()
                    .permitAll()
                    .failureUrl("/salirpafuera")
                    //.failureForwardUrl("/salirpafuera")
                    .and()
                .logout()
                    .logoutUrl("/salirpafuera")
                    .invalidateHttpSession(true)
                    .deleteCookies("JSESSIONID")
                    .logoutSuccessUrl("/");
        }
    } // FIN CONF WEB

This 2 static clases are inside my: @EnableWebSecurity public class CentralSecurityConfiguration {

The api methods are correctly annotated with Secure and PreAuthorize("isAuthenticated()")

UPDATE: The question may be clarified with this schema:

  • If user logins and doesn't have the proper role I want to move him to logout url (which deletes the session and redirects to root url). Now I get to generic error page.

If user logins and doesn't have the proper role I want to move him to logout url (which deletes the session and redirects to root url). Now I get to generic error page.

In general, you should seek to avoid exposing a logout page as a GET request, therefore redirecting to logout isn't recommended.

However, If I'm understanding your problem correctly, I believe you're receiving a 403 error when logging in successfully as a regular user after visiting an authenticated route that requires admin privileges (eg /admin/dashboard ). This is because an access denied error is distinct from an authentication failure.

Whether you want to redirect to logout or consider switching to an HTTP POST for normal logout, you will need to implement a custom AccessDeniedHandler , which can re-use the default AccessDeniedHandlerImpl .

http
    // ...
    .exceptionHandling().accessDeniedHandler(new LogoutAccessDeniedHandler("/")); // Redirect to root after logout

The LogoutAccessDeniedHandler would look something like this:

private static class LogoutAccessDeniedHandler implements AccessDeniedHandler {

    // Default handler does an internal forward to a specified URL
    private final AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();

    // CompositeLogoutHandler to perform logout activities like normal logout would
    private final LogoutHandler logoutHandler = new CompositeLogoutHandler(
            new CookieClearingLogoutHandler("JSESSIONID"),
            new SecurityContextLogoutHandler(),
            new LogoutSuccessEventPublishingLogoutHandler()
    );

    public LogoutAccessDeniedHandler(String errorPage) {
        accessDeniedHandler.setErrorPage(errorPage);
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        logoutHandler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
        accessDeniedHandler.handle(request, response, accessDeniedException);
    }

}

This diagram of how Spring Security handles exceptions may be helpful.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM